Skip to content

Commit 1b9f92f

Browse files
authored
operation_id_callback with blueprint name and func name (#224)
* operation_id_callback with blueprint name and func name * Add bp_name * Fix mypy * Update default value
1 parent a1cfc69 commit 1b9f92f

File tree

5 files changed

+27
-14
lines changed

5 files changed

+27
-14
lines changed

docs/Usage/Route_Operation.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ def create_book(body: BookBody):
3535

3636
## summary and description
3737

38-
You need to add docs to the view-func. The first line is the **summary**, and the rest is the **description**. Like this:
38+
You need to add docs to the view-func. The first line is the **summary**, and the rest is the **description**. Like
39+
this:
3940

4041
```python hl_lines="3 4 5 6"
4142
@app.get('/book/<int:bid>', tags=[book_tag], responses={200: BookResponse}, security=security)
@@ -67,7 +68,8 @@ def get_book(path: BookPath, query: BookBody):
6768

6869
Allows referencing an external resource for extended documentation.
6970

70-
More information to see [External Documentation Object](https://spec.openapis.org/oas/v3.1.0#external-documentation-object).
71+
More information to
72+
see [External Documentation Object](https://spec.openapis.org/oas/v3.1.0#external-documentation-object).
7173

7274
```python hl_lines="10"
7375
from flask_openapi3 import OpenAPI, ExternalDocumentation
@@ -110,7 +112,7 @@ Just add a `operation_id_callback` param to the constructor of `OpenAPI` or `AP
110112
The example shows setting the default `operation_id` to be the function name, in this case `create_book`.
111113

112114
```python hl_lines="6"
113-
def get_operation_id_for_path(*, name: str, path: str, method: str) -> str:
115+
def get_operation_id_for_path(*, bp_name: str = None, name: str, path: str, method: str) -> str:
114116
return name
115117

116118
api = APIBlueprint('book', __name__, url_prefix='/api', operation_id_callback=get_operation_id_for_path)
@@ -212,7 +214,8 @@ def create_book(body: BookBody):
212214

213215
## servers
214216

215-
An array of Server Objects, which provide connectivity information to a target server. If the server's property is not provided, or is an empty array, the default value would be a Server Object with an url value of /.
217+
An array of Server Objects, which provide connectivity information to a target server. If the server's property is not
218+
provided, or is an empty array, the default value would be a Server Object with an url value of /.
216219

217220
```python
218221
from flask_openapi3 import OpenAPI, Server
@@ -232,11 +235,10 @@ def get_book(path: BookPath):
232235

233236
## openapi_extensions
234237

235-
While the OpenAPI Specification tries to accommodate most use cases,
238+
While the OpenAPI Specification tries to accommodate most use cases,
236239
additional data can be added to extend the specification at certain points.
237240
See [Specification Extensions](https://spec.openapis.org/oas/v3.1.0#specification-extensions).
238241

239-
240242
```python hl_lines="3 12 19 28 42"
241243
from flask_openapi3 import OpenAPI, APIBlueprint, APIView
242244

flask_openapi3/blueprint.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
# @Author : llc
33
# @Time : 2022/4/1 16:54
4+
import inspect
45
from typing import Optional, Any, Callable
56

67
from flask import Blueprint
@@ -162,9 +163,10 @@ def _collect_openapi_info(
162163
operation.externalDocs = external_docs
163164

164165
# Unique string used to identify the operation.
165-
operation.operationId = operation_id or self.operation_id_callback(
166-
name=self.name, path=rule, method=method
167-
)
166+
operation_id_kwargs = {"name": func.__name__, "path": rule, "method": method}
167+
if "bp_name" in list(inspect.signature(self.operation_id_callback).parameters.keys()):
168+
operation_id_kwargs["bp_name"] = self.name
169+
operation.operationId = operation_id or self.operation_id_callback(**operation_id_kwargs)
168170

169171
# Only set `deprecated` if True, otherwise leave it as None
170172
if deprecated is not None:

flask_openapi3/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,22 @@ def get_operation(
102102
return operation
103103

104104

105-
def get_operation_id_for_path(*, name: str, path: str, method: str) -> str:
105+
def get_operation_id_for_path(*, bp_name: str = "", name: str = "", path: str = "", method: str = "") -> str:
106106
"""
107107
Generate a unique operation ID based on the name, path, and method.
108108
109109
Args:
110110
name: The name or identifier for the operation.
111111
path: The URL path for the operation.
112112
method: The HTTP method for the operation.
113+
bp_name: The Blueprint name
113114
114115
Returns:
115116
A unique operation ID generated based on the provided name, path, and method.
116117
117118
"""
118-
119+
if bp_name:
120+
name = bp_name + "_" + name
119121
return re.sub(r"\W", "_", name + path) + "_" + method.lower()
120122

121123

tests/test_api_blueprint.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
}
2020
security_schemes = {"jwt": jwt}
2121

22+
23+
def operation_id_callback(*, bp_name: str = None, name: str, path: str, method: str) -> str:
24+
assert bp_name == "/book"
25+
return name
26+
27+
2228
app = OpenAPI(__name__, info=info, security_schemes=security_schemes)
2329
app.config["TESTING"] = True
2430

@@ -37,7 +43,8 @@ class Unauthorized(BaseModel):
3743
url_prefix='/api',
3844
abp_tags=[tag],
3945
abp_security=security,
40-
abp_responses={"401": Unauthorized}
46+
abp_responses={"401": Unauthorized},
47+
operation_id_callback=operation_id_callback
4148
)
4249

4350
try:
@@ -104,7 +111,7 @@ def test_openapi(client):
104111
assert resp.status_code == 200
105112
assert resp.json == app.api_doc
106113
assert resp.json["paths"]["/api/book/{bid}"]["put"]["operationId"] == "update"
107-
assert resp.json["paths"]["/api/book/{bid}"]["delete"]["operationId"] == "_book_book__int_bid__delete"
114+
assert resp.json["paths"]["/api/book/{bid}"]["delete"]["operationId"] == "delete_book"
108115

109116

110117
def test_post(client):

tests/test_options_in_viewfunc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def test_openapi(client):
4949
assert resp.status_code == 200
5050
assert resp.json == app.api_doc
5151
assert resp.json["paths"]["/book"]["get"]["operationId"] == "get_book_book_get" # Default operation_id generator
52-
assert resp.json["paths"]["/api/book"]["post"]["operationId"] == "/book" # Custom callback operation_id
52+
assert resp.json["paths"]["/api/book"]["post"]["operationId"] == "create_book" # Custom callback operation_id
5353

5454

5555
def test_get(client):

0 commit comments

Comments
 (0)