from fastapi import FastAPI
+from fastapi.routing import APIRoute
app = FastAPI()
-@app.get("/items/", include_in_schema=False)
+@app.get("/items/")
async def read_items():
return [{"item_id": "Foo"}]
+
+
+def use_route_names_as_operation_ids(app: FastAPI) -> None:
+ """
+ Simplify operation IDs so that generated API clients have simpler function
+ names.
+
+ Should be called only after all routes have been added.
+ """
+ for route in app.routes:
+ if isinstance(route, APIRoute):
+ route.operation_id = route.name # in this case, 'read_items'
+
+
+use_route_names_as_operation_ids(app)
-from typing import Set
-
from fastapi import FastAPI
-from pydantic import BaseModel
app = FastAPI()
-class Item(BaseModel):
- name: str
- description: str = None
- price: float
- tax: float = None
- tags: Set[str] = []
-
-
-@app.post("/items/", response_model=Item, summary="Create an item")
-async def create_item(*, item: Item):
- """
- Create an item with all the information:
-
- - **name**: each item must have a name
- - **description**: a long description
- - **price**: required
- - **tax**: if the item doesn't have tax, you can omit this
- - **tags**: a set of unique tag strings for this item
- \f
- :param item: User input.
- """
- return item
+@app.get("/items/", include_in_schema=False)
+async def read_items():
+ return [{"item_id": "Foo"}]
--- /dev/null
+from typing import Set
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str = None
+ price: float
+ tax: float = None
+ tags: Set[str] = []
+
+
+@app.post("/items/", response_model=Item, summary="Create an item")
+async def create_item(*, item: Item):
+ """
+ Create an item with all the information:
+
+ - **name**: each item must have a name
+ - **description**: a long description
+ - **price**: required
+ - **tax**: if the item doesn't have tax, you can omit this
+ - **tags**: a set of unique tag strings for this item
+ \f
+ :param item: User input.
+ """
+ return item
{!./src/path_operation_advanced_configuration/tutorial001.py!}
```
+### Using the *path operation function* name as the operationId
+
+If you want to use your APIs' function names as `operationId`s, you can iterate over all of them and override each *path operation's* `operation_id` using their `APIRoute.name`.
+
+You should do it after adding all your *path operations*.
+
+```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24"
+{!./src/path_operation_advanced_configuration/tutorial002.py!}
+```
+
+!!! tip
+ If you manually call `app.openapi()`, you should update the `operationId`s before that.
+
+!!! warning
+ If you do this, you have to make sure each one of your *path operation functions* has a unique name.
+
+ Even if they are in different modules (Python files).
+
## Exclude from OpenAPI
To exclude a path operation from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`;
```Python hl_lines="6"
-{!./src/path_operation_advanced_configuration/tutorial002.py!}
+{!./src/path_operation_advanced_configuration/tutorial003.py!}
```
## Advanced description from docstring
It won't show up in the documentation, but other tools (such as Sphinx) will be able to use the rest.
```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29"
-{!./src/path_operation_advanced_configuration/tutorial003.py!}
+{!./src/path_operation_advanced_configuration/tutorial004.py!}
```
openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "Fast API", "version": "0.1.0"},
- "paths": {},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items",
+ }
+ }
+ },
}
openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "Fast API", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create an item",
- "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item\n",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"type": "string"},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
+ "paths": {},
}
assert response.json() == openapi_schema
-def test_query_params_str_validations():
- response = client.post("/items/", json={"name": "Foo", "price": 42})
+def test_get():
+ response = client.get("/items/")
assert response.status_code == 200
- assert response.json() == {
- "name": "Foo",
- "price": 42,
- "description": None,
- "tax": None,
- "tags": [],
- }
+ assert response.json() == [{"item_id": "Foo"}]
--- /dev/null
+from starlette.testclient import TestClient
+
+from path_operation_advanced_configuration.tutorial004 import app
+
+client = TestClient(app)
+
+openapi_schema = {
+ "openapi": "3.0.2",
+ "info": {"title": "Fast API", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item\n",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == openapi_schema
+
+
+def test_query_params_str_validations():
+ response = client.post("/items/", json={"name": "Foo", "price": 42})
+ assert response.status_code == 200
+ assert response.json() == {
+ "name": "Foo",
+ "price": 42,
+ "description": None,
+ "tax": None,
+ "tags": [],
+ }