跳转至

APIView

APIView ⚓︎

Source code in flask_openapi3/view.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
class APIView:
    def __init__(
        self,
        url_prefix: str | None = None,
        view_tags: list[Tag] | None = None,
        view_security: list[dict[str, list[str]]] | None = None,
        view_responses: ResponseDict | None = None,
        doc_ui: bool = True,
        operation_id_callback: Callable = get_operation_id_for_path,
        validate_response: bool | None = None,
    ):
        """
        Create a class-based view

        Args:
            url_prefix: A path to prepend to all the APIView's urls
            view_tags: APIView tags for every API.
            view_security: APIView security for every API.
            view_responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
            doc_ui: Enable OpenAPI document UI (Swagger UI and Redoc). Defaults to True.
            operation_id_callback: Callback function for custom operation_id generation.
                                   Receives name (str), path (str) and method (str) parameters.
                                   Defaults to `get_operation_id_for_path` from utils
            validate_response: Verify the response body.
        """
        self.url_prefix = url_prefix
        self.view_tags = view_tags or []
        self.view_security = view_security or []

        # Convert key to string
        self.view_responses = convert_responses_key_to_string(view_responses or {})

        self.doc_ui = doc_ui
        self.operation_id_callback: Callable = operation_id_callback

        self.views: dict = dict()
        self.paths: dict = dict()
        self.components_schemas: dict = dict()
        self.tags: list[Tag] = []
        self.tag_names: list[str] = []

        self.validate_response = validate_response

    def route(self, rule: str):
        """Decorator for view class"""

        def wrapper(cls):
            if self.views.get(rule):  # pragma: no cover
                raise ValueError(f"malformed url rule: {rule!r}")
            methods = []

            # Parse rule: merge url_prefix and format rule from /pet/<petId> to /pet/{petId}
            uri = parse_rule(rule, url_prefix=self.url_prefix)

            for method in HTTPMethod:
                cls_method = getattr(cls, method.lower(), None)
                if not cls_method:
                    continue
                methods.append(method)
                if self.doc_ui is False:
                    continue
                if not getattr(cls_method, "operation", None):
                    continue
                # Parse method
                parse_method(uri, method, self.paths, cls_method.operation)
                # Update operation_id
                if not cls_method.operation.operationId:
                    cls_method.operation.operationId = self.operation_id_callback(
                        name=cls_method.__qualname__, path=rule, method=method
                    )

            # Convert route parameters from {param} to <param>
            _rule = uri.replace("{", "<").replace("}", ">")
            self.views[_rule] = (cls, methods)

            return cls

        return wrapper

    def doc(
        self,
        *,
        tags: list[Tag] | None = None,
        summary: str | None = None,
        description: str | None = None,
        external_docs: ExternalDocumentation | None = None,
        operation_id: str | None = None,
        responses: ResponseDict | None = None,
        deprecated: bool | None = None,
        security: list[dict[str, list[Any]]] | None = None,
        servers: list[Server] | None = None,
        openapi_extensions: dict[str, Any] | None = None,
        validate_response: bool | None = None,
        doc_ui: bool = True,
    ) -> Callable:
        """
        Decorator for view method.
        More information goto https://spec.openapis.org/oas/v3.1.0#operation-object

        Args:
            tags: Adds metadata to a single tag.
            summary: A short summary of what the operation does.
            description: A verbose explanation of the operation behavior.
            external_docs: Additional external documentation for this operation.
            operation_id: Unique string used to identify the operation.
            responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
            deprecated: Declares this operation to be deprecated.
            security: A declaration of which security mechanisms can be used for this operation.
            servers: An alternative server array to service this operation.
            openapi_extensions: Allows extensions to the OpenAPI Schema.
            doc_ui: Declares this operation to be shown. Default to True.
            validate_response: Verify the response body.
        """

        new_responses = convert_responses_key_to_string(responses or {})
        security = security or []
        tags = tags + self.view_tags if tags else self.view_tags

        def decorator(func):
            func.validate_response = validate_response
            func.responses = responses

            if self.doc_ui is False or doc_ui is False:
                return func

            # Global response combines API responses
            combine_responses = {**self.view_responses, **new_responses}

            # Create operation
            operation = get_operation(
                func, summary=summary, description=description, openapi_extensions=openapi_extensions
            )

            # Set external docs
            if external_docs:
                operation.externalDocs = external_docs

            # Unique string used to identify the operation.
            if operation_id:
                operation.operationId = operation_id

            # Only set `deprecated` if True, otherwise leave it as None
            if deprecated is not None:
                operation.deprecated = deprecated

            # Add security
            _security = (security or []) + self.view_security or None
            if _security:
                operation.security = _security

            # Add servers
            if servers:
                operation.servers = servers

            # Store tags
            parse_and_store_tags(tags, self.tags, self.tag_names, operation)

            # Parse parameters
            parse_parameters(func, components_schemas=self.components_schemas, operation=operation)

            # Parse response
            get_responses(combine_responses, self.components_schemas, operation)
            func.operation = operation

            return func

        return decorator

    def register(
        self, app: "OpenAPI", url_prefix: str | None = None, view_kwargs: dict[Any, Any] | None = None
    ) -> None:
        """
        Register the API views with the given OpenAPI app.

        Args:
            app: An instance of the OpenAPI app.
            url_prefix: A path to prepend to all the APIView's urls
            view_kwargs: Additional keyword arguments to pass to the API views.
        """
        for rule, (cls, methods) in self.views.items():
            for method in methods:
                func = getattr(cls, method.lower())
                if func.validate_response is not None:
                    _validate_response = func.validate_response
                else:
                    _validate_response = self.validate_response
                header, cookie, path, query, form, body, raw = parse_parameters(func, doc_ui=False)
                view_func = app.create_view_func(
                    func,
                    header,
                    cookie,
                    path,
                    query,
                    form,
                    body,
                    raw,
                    view_class=cls,
                    view_kwargs=view_kwargs,
                    responses=func.responses,
                    validate_response=_validate_response,
                )

                if url_prefix and self.url_prefix and url_prefix != self.url_prefix:
                    rule = url_prefix + rule.removeprefix(self.url_prefix)
                elif url_prefix and not self.url_prefix:
                    rule = url_prefix.rstrip("/") + "/" + rule.lstrip("/")

                options = {"endpoint": cls.__name__ + "." + method.lower(), "methods": [method.upper()]}
                app.add_url_rule(rule, view_func=view_func, **options)

__init__(url_prefix=None, view_tags=None, view_security=None, view_responses=None, doc_ui=True, operation_id_callback=get_operation_id_for_path, validate_response=None) ⚓︎

Create a class-based view

Parameters:

Name Type Description Default
url_prefix str | None

A path to prepend to all the APIView's urls

None
view_tags list[Tag] | None

APIView tags for every API.

None
view_security list[dict[str, list[str]]] | None

APIView security for every API.

None
view_responses ResponseDict | None

API responses should be either a subclass of BaseModel, a dictionary, or None.

None
doc_ui bool

Enable OpenAPI document UI (Swagger UI and Redoc). Defaults to True.

True
operation_id_callback Callable

Callback function for custom operation_id generation. Receives name (str), path (str) and method (str) parameters. Defaults to get_operation_id_for_path from utils

get_operation_id_for_path
validate_response bool | None

Verify the response body.

None
Source code in flask_openapi3/view.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def __init__(
    self,
    url_prefix: str | None = None,
    view_tags: list[Tag] | None = None,
    view_security: list[dict[str, list[str]]] | None = None,
    view_responses: ResponseDict | None = None,
    doc_ui: bool = True,
    operation_id_callback: Callable = get_operation_id_for_path,
    validate_response: bool | None = None,
):
    """
    Create a class-based view

    Args:
        url_prefix: A path to prepend to all the APIView's urls
        view_tags: APIView tags for every API.
        view_security: APIView security for every API.
        view_responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
        doc_ui: Enable OpenAPI document UI (Swagger UI and Redoc). Defaults to True.
        operation_id_callback: Callback function for custom operation_id generation.
                               Receives name (str), path (str) and method (str) parameters.
                               Defaults to `get_operation_id_for_path` from utils
        validate_response: Verify the response body.
    """
    self.url_prefix = url_prefix
    self.view_tags = view_tags or []
    self.view_security = view_security or []

    # Convert key to string
    self.view_responses = convert_responses_key_to_string(view_responses or {})

    self.doc_ui = doc_ui
    self.operation_id_callback: Callable = operation_id_callback

    self.views: dict = dict()
    self.paths: dict = dict()
    self.components_schemas: dict = dict()
    self.tags: list[Tag] = []
    self.tag_names: list[str] = []

    self.validate_response = validate_response

doc(*, tags=None, summary=None, description=None, external_docs=None, operation_id=None, responses=None, deprecated=None, security=None, servers=None, openapi_extensions=None, validate_response=None, doc_ui=True) ⚓︎

Decorator for view method. More information goto https://spec.openapis.org/oas/v3.1.0#operation-object

Parameters:

Name Type Description Default
tags list[Tag] | None

Adds metadata to a single tag.

None
summary str | None

A short summary of what the operation does.

None
description str | None

A verbose explanation of the operation behavior.

None
external_docs ExternalDocumentation | None

Additional external documentation for this operation.

None
operation_id str | None

Unique string used to identify the operation.

None
responses ResponseDict | None

API responses should be either a subclass of BaseModel, a dictionary, or None.

None
deprecated bool | None

Declares this operation to be deprecated.

None
security list[dict[str, list[Any]]] | None

A declaration of which security mechanisms can be used for this operation.

None
servers list[Server] | None

An alternative server array to service this operation.

None
openapi_extensions dict[str, Any] | None

Allows extensions to the OpenAPI Schema.

None
doc_ui bool

Declares this operation to be shown. Default to True.

True
validate_response bool | None

Verify the response body.

None
Source code in flask_openapi3/view.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
def doc(
    self,
    *,
    tags: list[Tag] | None = None,
    summary: str | None = None,
    description: str | None = None,
    external_docs: ExternalDocumentation | None = None,
    operation_id: str | None = None,
    responses: ResponseDict | None = None,
    deprecated: bool | None = None,
    security: list[dict[str, list[Any]]] | None = None,
    servers: list[Server] | None = None,
    openapi_extensions: dict[str, Any] | None = None,
    validate_response: bool | None = None,
    doc_ui: bool = True,
) -> Callable:
    """
    Decorator for view method.
    More information goto https://spec.openapis.org/oas/v3.1.0#operation-object

    Args:
        tags: Adds metadata to a single tag.
        summary: A short summary of what the operation does.
        description: A verbose explanation of the operation behavior.
        external_docs: Additional external documentation for this operation.
        operation_id: Unique string used to identify the operation.
        responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
        deprecated: Declares this operation to be deprecated.
        security: A declaration of which security mechanisms can be used for this operation.
        servers: An alternative server array to service this operation.
        openapi_extensions: Allows extensions to the OpenAPI Schema.
        doc_ui: Declares this operation to be shown. Default to True.
        validate_response: Verify the response body.
    """

    new_responses = convert_responses_key_to_string(responses or {})
    security = security or []
    tags = tags + self.view_tags if tags else self.view_tags

    def decorator(func):
        func.validate_response = validate_response
        func.responses = responses

        if self.doc_ui is False or doc_ui is False:
            return func

        # Global response combines API responses
        combine_responses = {**self.view_responses, **new_responses}

        # Create operation
        operation = get_operation(
            func, summary=summary, description=description, openapi_extensions=openapi_extensions
        )

        # Set external docs
        if external_docs:
            operation.externalDocs = external_docs

        # Unique string used to identify the operation.
        if operation_id:
            operation.operationId = operation_id

        # Only set `deprecated` if True, otherwise leave it as None
        if deprecated is not None:
            operation.deprecated = deprecated

        # Add security
        _security = (security or []) + self.view_security or None
        if _security:
            operation.security = _security

        # Add servers
        if servers:
            operation.servers = servers

        # Store tags
        parse_and_store_tags(tags, self.tags, self.tag_names, operation)

        # Parse parameters
        parse_parameters(func, components_schemas=self.components_schemas, operation=operation)

        # Parse response
        get_responses(combine_responses, self.components_schemas, operation)
        func.operation = operation

        return func

    return decorator

register(app, url_prefix=None, view_kwargs=None) ⚓︎

Register the API views with the given OpenAPI app.

Parameters:

Name Type Description Default
app OpenAPI

An instance of the OpenAPI app.

required
url_prefix str | None

A path to prepend to all the APIView's urls

None
view_kwargs dict[Any, Any] | None

Additional keyword arguments to pass to the API views.

None
Source code in flask_openapi3/view.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def register(
    self, app: "OpenAPI", url_prefix: str | None = None, view_kwargs: dict[Any, Any] | None = None
) -> None:
    """
    Register the API views with the given OpenAPI app.

    Args:
        app: An instance of the OpenAPI app.
        url_prefix: A path to prepend to all the APIView's urls
        view_kwargs: Additional keyword arguments to pass to the API views.
    """
    for rule, (cls, methods) in self.views.items():
        for method in methods:
            func = getattr(cls, method.lower())
            if func.validate_response is not None:
                _validate_response = func.validate_response
            else:
                _validate_response = self.validate_response
            header, cookie, path, query, form, body, raw = parse_parameters(func, doc_ui=False)
            view_func = app.create_view_func(
                func,
                header,
                cookie,
                path,
                query,
                form,
                body,
                raw,
                view_class=cls,
                view_kwargs=view_kwargs,
                responses=func.responses,
                validate_response=_validate_response,
            )

            if url_prefix and self.url_prefix and url_prefix != self.url_prefix:
                rule = url_prefix + rule.removeprefix(self.url_prefix)
            elif url_prefix and not self.url_prefix:
                rule = url_prefix.rstrip("/") + "/" + rule.lstrip("/")

            options = {"endpoint": cls.__name__ + "." + method.lower(), "methods": [method.upper()]}
            app.add_url_rule(rule, view_func=view_func, **options)

route(rule) ⚓︎

Decorator for view class

Source code in flask_openapi3/view.py
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def route(self, rule: str):
    """Decorator for view class"""

    def wrapper(cls):
        if self.views.get(rule):  # pragma: no cover
            raise ValueError(f"malformed url rule: {rule!r}")
        methods = []

        # Parse rule: merge url_prefix and format rule from /pet/<petId> to /pet/{petId}
        uri = parse_rule(rule, url_prefix=self.url_prefix)

        for method in HTTPMethod:
            cls_method = getattr(cls, method.lower(), None)
            if not cls_method:
                continue
            methods.append(method)
            if self.doc_ui is False:
                continue
            if not getattr(cls_method, "operation", None):
                continue
            # Parse method
            parse_method(uri, method, self.paths, cls_method.operation)
            # Update operation_id
            if not cls_method.operation.operationId:
                cls_method.operation.operationId = self.operation_id_callback(
                    name=cls_method.__qualname__, path=rule, method=method
                )

        # Convert route parameters from {param} to <param>
        _rule = uri.replace("{", "<").replace("}", ">")
        self.views[_rule] = (cls, methods)

        return cls

    return wrapper