authentik.api.validation

 1from collections.abc import Callable
 2from functools import wraps
 3from typing import Literal
 4
 5from rest_framework.request import Request
 6from rest_framework.response import Response
 7from rest_framework.serializers import Serializer
 8from rest_framework.viewsets import ViewSet
 9
10
11def validate(serializer_type: type[Serializer], location: Literal["body", "query"] = "body"):
12    """Validate incoming data with the specified serializer. Raw data can either be taken
13    from request body or query string, defaulting to body.
14
15    Validated data is added to the function this decorator is used on with a named parameter
16    based on the location of the data.
17
18    Example:
19
20        @validate(MySerializer)
21        @validate(MyQuerySerializer, location="query")
22        def my_action(self, request, *, body: MySerializer, query: MyQuerySerializer):
23            ...
24
25    """
26
27    def wrapper_outer(func: Callable):
28
29        @wraps(func)
30        def wrapper(self: ViewSet, request: Request, *args, **kwargs) -> Response:
31            data = {}
32            if location == "body":
33                data = request.data
34            elif location == "query":
35                data = request.query_params
36            else:
37                raise ValueError(f"Invalid data location '{location}'")
38            instance = serializer_type(
39                data=data,
40                context={
41                    "request": request,
42                },
43            )
44            instance.is_valid(raise_exception=True)
45            kwargs[location] = instance
46            return func(self, request, *args, **kwargs)
47
48        return wrapper
49
50    return wrapper_outer
def validate( serializer_type: type[rest_framework.serializers.Serializer], location: Literal['body', 'query'] = 'body'):
12def validate(serializer_type: type[Serializer], location: Literal["body", "query"] = "body"):
13    """Validate incoming data with the specified serializer. Raw data can either be taken
14    from request body or query string, defaulting to body.
15
16    Validated data is added to the function this decorator is used on with a named parameter
17    based on the location of the data.
18
19    Example:
20
21        @validate(MySerializer)
22        @validate(MyQuerySerializer, location="query")
23        def my_action(self, request, *, body: MySerializer, query: MyQuerySerializer):
24            ...
25
26    """
27
28    def wrapper_outer(func: Callable):
29
30        @wraps(func)
31        def wrapper(self: ViewSet, request: Request, *args, **kwargs) -> Response:
32            data = {}
33            if location == "body":
34                data = request.data
35            elif location == "query":
36                data = request.query_params
37            else:
38                raise ValueError(f"Invalid data location '{location}'")
39            instance = serializer_type(
40                data=data,
41                context={
42                    "request": request,
43                },
44            )
45            instance.is_valid(raise_exception=True)
46            kwargs[location] = instance
47            return func(self, request, *args, **kwargs)
48
49        return wrapper
50
51    return wrapper_outer

Validate incoming data with the specified serializer. Raw data can either be taken from request body or query string, defaulting to body.

Validated data is added to the function this decorator is used on with a named parameter based on the location of the data.

Example:

@validate(MySerializer)
@validate(MyQuerySerializer, location="query")
def my_action(self, request, *, body: MySerializer, query: MyQuerySerializer):
    ...