跳转至

APIView

APIView ⚓︎

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
 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
class APIView:
    def __init__(
            self,
            url_prefix: Optional[str] = None,
            view_tags: Optional[List[Tag]] = None,
            view_security: Optional[List[Dict[str, List[str]]]] = None,
            view_responses: Optional[ResponseDict] = None,
            doc_ui: bool = True,
            operation_id_callback: Callable = get_operation_id_for_path,
    ):
        """
        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
        """
        self.url_prefix = url_prefix
        self.view_tags = view_tags or []
        self.view_security = view_security or []

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

        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] = []

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

        def wrapper(cls):
            if self.views.get(rule):
                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: Optional[List[Tag]] = None,
            summary: Optional[str] = None,
            description: Optional[str] = None,
            external_docs: Optional[ExternalDocumentation] = None,
            operation_id: Optional[str] = None,
            responses: Optional[ResponseDict] = None,
            deprecated: Optional[bool] = None,
            security: Optional[List[Dict[str, List[Any]]]] = None,
            servers: Optional[List[Server]] = None,
            openapi_extensions: Optional[Dict[str, Any]] = 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.
        """

        if responses is None:
            new_responses = {}
        else:
            # Convert key to string
            new_responses = convert_responses_key_to_string(responses)
        if security is None:
            security = []
        tags = tags + self.view_tags if tags else self.view_tags

        def decorator(func):
            if self.doc_ui is False or doc_ui is False:
                return
            # Global response combines API responses
            combine_responses = deepcopy(self.view_responses)
            combine_responses.update(**new_responses)
            # Create operation
            operation = get_operation(
                func,
                summary=summary,
                description=description,
                openapi_extensions=openapi_extensions
            )
            # Set external docs
            operation.externalDocs = external_docs
            # Unique string used to identify the operation.
            operation.operationId = operation_id
            # Only set `deprecated` if True, otherwise leave it as None
            operation.deprecated = deprecated
            # Add security
            operation.security = security + self.view_security or None
            # Add 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", view_kwargs: Optional[Dict[Any, Any]] = None) -> None:
        """
        Register the API views with the given OpenAPI app.

        Args:
            app: An instance of the OpenAPI app.
            view_kwargs: Additional keyword arguments to pass to the API views.
        """
        if view_kwargs is None:
            view_kwargs = {}
        for rule, (cls, methods) in self.views.items():
            for method in methods:
                func = getattr(cls, method.lower())
                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
                )
                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) ⚓︎

Create a class-based view

Parameters:

Name Type Description Default
url_prefix Optional[str]

A path to prepend to all the APIView's urls

None
view_tags Optional[List[Tag]]

APIView tags for every API.

None
view_security Optional[List[Dict[str, List[str]]]]

APIView security for every API.

None
view_responses Optional[ResponseDict]

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
Source code in flask_openapi3/view.py
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
def __init__(
        self,
        url_prefix: Optional[str] = None,
        view_tags: Optional[List[Tag]] = None,
        view_security: Optional[List[Dict[str, List[str]]]] = None,
        view_responses: Optional[ResponseDict] = None,
        doc_ui: bool = True,
        operation_id_callback: Callable = get_operation_id_for_path,
):
    """
    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
    """
    self.url_prefix = url_prefix
    self.view_tags = view_tags or []
    self.view_security = view_security or []

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

    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] = []

doc(*, tags=None, summary=None, description=None, external_docs=None, operation_id=None, responses=None, deprecated=None, security=None, servers=None, openapi_extensions=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 Optional[List[Tag]]

Adds metadata to a single tag.

None
summary Optional[str]

A short summary of what the operation does.

None
description Optional[str]

A verbose explanation of the operation behavior.

None
external_docs Optional[ExternalDocumentation]

Additional external documentation for this operation.

None
operation_id Optional[str]

Unique string used to identify the operation.

None
responses Optional[ResponseDict]

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

None
deprecated Optional[bool]

Declares this operation to be deprecated.

None
security Optional[List[Dict[str, List[Any]]]]

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

None
servers Optional[List[Server]]

An alternative server array to service this operation.

None
openapi_extensions Optional[Dict[str, Any]]

Allows extensions to the OpenAPI Schema.

None
doc_ui bool

Declares this operation to be shown. Default to True.

True
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
def doc(
        self,
        *,
        tags: Optional[List[Tag]] = None,
        summary: Optional[str] = None,
        description: Optional[str] = None,
        external_docs: Optional[ExternalDocumentation] = None,
        operation_id: Optional[str] = None,
        responses: Optional[ResponseDict] = None,
        deprecated: Optional[bool] = None,
        security: Optional[List[Dict[str, List[Any]]]] = None,
        servers: Optional[List[Server]] = None,
        openapi_extensions: Optional[Dict[str, Any]] = 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.
    """

    if responses is None:
        new_responses = {}
    else:
        # Convert key to string
        new_responses = convert_responses_key_to_string(responses)
    if security is None:
        security = []
    tags = tags + self.view_tags if tags else self.view_tags

    def decorator(func):
        if self.doc_ui is False or doc_ui is False:
            return
        # Global response combines API responses
        combine_responses = deepcopy(self.view_responses)
        combine_responses.update(**new_responses)
        # Create operation
        operation = get_operation(
            func,
            summary=summary,
            description=description,
            openapi_extensions=openapi_extensions
        )
        # Set external docs
        operation.externalDocs = external_docs
        # Unique string used to identify the operation.
        operation.operationId = operation_id
        # Only set `deprecated` if True, otherwise leave it as None
        operation.deprecated = deprecated
        # Add security
        operation.security = security + self.view_security or None
        # Add 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, 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
view_kwargs Optional[Dict[Any, Any]]

Additional keyword arguments to pass to the API views.

None
Source code in flask_openapi3/view.py
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
def register(self, app: "OpenAPI", view_kwargs: Optional[Dict[Any, Any]] = None) -> None:
    """
    Register the API views with the given OpenAPI app.

    Args:
        app: An instance of the OpenAPI app.
        view_kwargs: Additional keyword arguments to pass to the API views.
    """
    if view_kwargs is None:
        view_kwargs = {}
    for rule, (cls, methods) in self.views.items():
        for method in methods:
            func = getattr(cls, method.lower())
            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
            )
            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
 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
def route(self, rule: str):
    """Decorator for view class"""

    def wrapper(cls):
        if self.views.get(rule):
            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