Passed
Pull Request — main (#879)
by Juho
07:12 queued 04:02
created

CustomFormDataValidator.__init__()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 3
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
"""Custom validator for the Annif API."""
2
3
from __future__ import annotations
4
5
import logging
6
from typing import Any
7
8
from connexion.exceptions import BadRequestProblem, ExtraParameterProblem
9
from connexion.json_schema import format_error_with_path
10
from connexion.validators import FormDataValidator, JSONRequestBodyValidator
11
from jsonschema.exceptions import ValidationError
12
13
logger = logging.getLogger("openapi.validation")
14
15
16
class CustomRequestBodyValidator(JSONRequestBodyValidator):
17
    """Custom request body validator that overrides the default error message for the
18
    'maxItems' validator for the 'documents' property to prevent logging request body
19
    with the contents of all documents."""
20
21
    def __init__(self, *args, **kwargs) -> None:
22
        super().__init__(*args, **kwargs)
23
24
    def _validate(self, body: Any) -> dict | None:
25
        try:
26
            return self._validator.validate(body)
27
        except ValidationError as exception:
28
            if exception.validator == "maxItems" and list(exception.schema_path) == [
29
                "properties",
30
                "documents",
31
                "maxItems",
32
            ]:
33
                exception.message = "too many items"
34
            error_path_msg = format_error_with_path(exception=exception)
35
            logger.error(
36
                f"Validation error: {exception.message}{error_path_msg}",
37
                extra={"validator": "body"},
38
            )
39
            raise BadRequestProblem(detail=f"{exception.message}{error_path_msg}")
40
41
42
class CustomFormDataValidator(FormDataValidator):
43
    """Custom request body validator that allows additional metadata fields starting
44
    with 'metadata_' in the request body while rejecting other fields."""
45
46
    def __init__(self, *args, **kwargs) -> None:
47
        super().__init__(*args, **kwargs)
48
49
    def _validate_params_strictly(self, data: dict) -> None:
50
        form_params = data.keys()
51
        spec_params = self._schema.get("properties", {}).keys()
52
53
        reduced_form_params = [
54
            fp for fp in form_params if not fp.startswith("metadata_")
55
        ]
56
57
        errors = set(reduced_form_params).difference(set(spec_params))
58
        if errors:
59
            raise ExtraParameterProblem(param_type="formData", extra_params=errors)
60