跳转至

# 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

    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())
                    _validate_response = getattr(func, "validate_response", None) or 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

    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())
                _validate_response = getattr(func, "validate_response", None) or 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