Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/en/docs/img/tutorial/metadata/image02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions docs/en/docs/tutorial/metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,58 @@ With this configuration, the automatic API docs would look like:

<img src="/img/tutorial/metadata/image01.png">

## Tag descriptions

You can also add additional metadata for the different tags used to group your path operations with the parameter `openapi_tags`.

It takes a list containing one dictionary for each tag.

Each dictionary can contain:

* `name` (**required**): a `str` with the same tag name you use in the `tags` parameter in your *path operations* and `APIRouter`s.
* `description`: a `str` with a short description for the tag. It can have Markdown and will be shown in the docs UI.
* `externalDocs`: a `dict` describing external documentation with:
* `description`: a `str` with a short description for the external docs.
* `url` (**required**): a `str` with the URL for the external documentation.

### Create metadata for tags

Let's try that in an example with tags for `users` and `items`.

Create metadata for your tags and pass it to the `openapi_tags` parameter:

```Python hl_lines="3 4 5 6 7 8 9 10 11 12 13 14 15 16 18"
{!../../../docs_src/metadata/tutorial004.py!}
```

Notice that you can use Markdown inside of the descriptions, for example "login" will be shown in bold (**login**) and "fancy" will be shown in italics (_fancy_).

!!! tip
You don't have to add metadata for all the tags that you use.

### Use your tags

Use the `tags` parameter with your *path operations* (and `APIRouter`s) to assign them to different tags:

```Python hl_lines="21 26"
{!../../../docs_src/metadata/tutorial004.py!}
```

!!! info
Read more about tags in [Path Operation Configuration](../path-operation-configuration/#tags){.internal-link target=_blank}.

### Check the docs

Now, if you check the docs, they will show all the additional metadata:

<img src="/img/tutorial/metadata/image02.png">

### Order of tags

The order of each tag metadata dictionary also defines the order shown in the docs UI.

For example, even though `users` would go after `items` in alphabetical order, it is shown before them, because we added their metadata as the first dictionary in the list.

## OpenAPI URL

By default, the OpenAPI schema is served at `/openapi.json`.
Expand Down
28 changes: 28 additions & 0 deletions docs_src/metadata/tutorial004.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from fastapi import FastAPI

tags_metadata = [
{
"name": "users",
"description": "Operations with users. The **login** logic is also here.",
},
{
"name": "items",
"description": "Manage items. So _fancy_ they have their own docs.",
"externalDocs": {
"description": "Items external docs",
"url": "https://fastapi.tiangolo.com/",
},
},
]

app = FastAPI(openapi_tags=tags_metadata)


@app.get("/users/", tags=["users"])
async def get_users():
return [{"name": "Harry"}, {"name": "Ron"}]


@app.get("/items/", tags=["items"])
async def get_items():
return [{"name": "wand"}, {"name": "flying broom"}]
3 changes: 3 additions & 0 deletions fastapi/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(
description: str = "",
version: str = "0.1.0",
openapi_url: Optional[str] = "/openapi.json",
openapi_tags: Optional[List[Dict[str, Any]]] = None,
default_response_class: Type[Response] = JSONResponse,
docs_url: Optional[str] = "/docs",
redoc_url: Optional[str] = "/redoc",
Expand Down Expand Up @@ -70,6 +71,7 @@ def __init__(
self.description = description
self.version = version
self.openapi_url = openapi_url
self.openapi_tags = openapi_tags
# TODO: remove when discarding the openapi_prefix parameter
if openapi_prefix:
logger.warning(
Expand Down Expand Up @@ -103,6 +105,7 @@ def openapi(self, openapi_prefix: str = "") -> Dict:
description=self.description,
routes=self.routes,
openapi_prefix=openapi_prefix,
tags=self.openapi_tags,
)
return self.openapi_schema

Expand Down
7 changes: 5 additions & 2 deletions fastapi/openapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,12 +317,13 @@ def get_openapi(
openapi_version: str = "3.0.2",
description: str = None,
routes: Sequence[BaseRoute],
openapi_prefix: str = ""
openapi_prefix: str = "",
tags: Optional[List[Dict[str, Any]]] = None
) -> Dict:
info = {"title": title, "version": version}
if description:
info["description"] = description
output = {"openapi": openapi_version, "info": info}
output: Dict[str, Any] = {"openapi": openapi_version, "info": info}
components: Dict[str, Dict] = {}
paths: Dict[str, Dict] = {}
flat_models = get_flat_models_from_routes(routes)
Expand Down Expand Up @@ -352,4 +353,6 @@ def get_openapi(
if components:
output["components"] = components
output["paths"] = paths
if tags:
output["tags"] = tags
return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True)
1 change: 0 additions & 1 deletion fastapi/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
)
from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
from fastapi.logger import logger
from fastapi.openapi.constants import STATUS_CODES_WITH_NO_BODY
from fastapi.utils import (
PYDANTIC_1,
Expand Down
65 changes: 65 additions & 0 deletions tests/test_tutorial/test_metadata/test_tutorial004.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from fastapi.testclient import TestClient

from metadata.tutorial004 import app

client = TestClient(app)

openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
"get": {
"tags": ["users"],
"summary": "Get Users",
"operationId": "get_users_users__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
},
"/items/": {
"get": {
"tags": ["items"],
"summary": "Get Items",
"operationId": "get_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
},
},
"tags": [
{
"name": "users",
"description": "Operations with users. The **login** logic is also here.",
},
{
"name": "items",
"description": "Manage items. So _fancy_ they have their own docs.",
"externalDocs": {
"description": "Items external docs",
"url": "https://fastapi.tiangolo.com/",
},
},
],
}


def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == openapi_schema


def test_path_operations():
response = client.get("/items/")
assert response.status_code == 200, response.text
response = client.get("/users/")
assert response.status_code == 200, response.text