diff --git a/docs/src/bigger_applications/app/main.py b/docs/src/bigger_applications/app/main.py
index 4e614a007..baec2aac0 100644
--- a/docs/src/bigger_applications/app/main.py
+++ b/docs/src/bigger_applications/app/main.py
@@ -1,9 +1,9 @@
from fastapi import FastAPI
-from .routers.items import router as items_router
-from .routers.users import router as users_router
+from .routers import items
+from .routers import users
app = FastAPI()
-app.include_router(users_router)
-app.include_router(items_router, prefix="/items")
+app.include_router(users.router)
+app.include_router(items.router, prefix="/items", tags=["items"])
diff --git a/docs/src/bigger_applications/app/routers/items.py b/docs/src/bigger_applications/app/routers/items.py
index 2297e2d27..46a241902 100644
--- a/docs/src/bigger_applications/app/routers/items.py
+++ b/docs/src/bigger_applications/app/routers/items.py
@@ -3,11 +3,11 @@ from fastapi import APIRouter
router = APIRouter()
-@router.get("/", tags=["items"])
+@router.get("/")
async def read_items():
return [{"name": "Item Foo"}, {"name": "item Bar"}]
-@router.get("/{item_id}", tags=["items"])
+@router.get("/{item_id}")
async def read_item(item_id: str):
return {"name": "Fake Specific Item", "item_id": item_id}
diff --git a/docs/tutorial/bigger-applications.md b/docs/tutorial/bigger-applications.md
index 74d46739a..e8a23613d 100644
--- a/docs/tutorial/bigger-applications.md
+++ b/docs/tutorial/bigger-applications.md
@@ -2,6 +2,8 @@ If you are building an application or a web API, it's rarely the case that you c
**FastAPI** provides a convenience tool to structure your application while keeping all the flexibility.
+!!! info
+ If you come from Flask, this would be the equivalent of Flask's Blueprints.
## An example file structure
@@ -99,13 +101,12 @@ It's all the same structure as with `app/routers/users.py`.
But let's say that this time we are more lazy.
-And we don't want to have to explicitly type `/items/` in every path operation, we can do it later:
+And we don't want to have to explicitly type `/items/` and `tags=["items"]` in every *path operation* (we will be able to do it later):
```Python hl_lines="6 11 16"
{!./src/bigger_applications/app/routers/items.py!}
```
-
## The main `FastAPI`
Now, let's see the module at `app/main.py`.
@@ -124,9 +125,9 @@ You import and create a `FastAPI` class as normally:
### Import the `APIRouter`
-But this time we are not adding path operations directly with the `FastAPI` `app`.
+But this time we are not adding *path operations* directly with the `FastAPI` `app`.
-We import the `APIRouter`s from the other files:
+We import the other submodules that have `APIRouter`s:
```Python hl_lines="3 4"
{!./src/bigger_applications/app/main.py!}
@@ -140,22 +141,21 @@ As the file `app/routers/items.py` is part of the same Python package, we can im
The section:
```Python
-from .routers.items import router
+from .routers import items
```
Means:
* Starting in the same package that this module (the file `app/main.py`) lives in (the directory `app/`)...
* look for the subpackage `routers` (the directory at `app/routers/`)...
-* and from it, the submodule `items` (the file at `app/routers/items.py`)...
-* and from that submodule, import the variable `router`.
+* and from it, import the submodule `items` (the file at `app/routers/items.py`)...
-The variable `router` is the same one we created in the file `app/routers/items.py`. It's an `APIRouter`.
+The module `items` will have a variable `router` (`items.router`). This is the same one we created in the file `app/routers/items.py`. It's an `APIRouter`.
We could also import it like:
```Python
-from app.routers.items import router
+from app.routers import items
```
!!! info
@@ -168,20 +168,20 @@ from app.routers.items import router
### Avoid name collisions
-We are importing a variable named `router` from the submodule `items`.
+We are importing the submodule `items` directly, instead of importing just its variable `router`.
-But we also have another variable named `router` in the submodule `users`.
+This is because we also have another variable named `router` in the submodule `users`.
-If we import one after the other, like:
+If we had imported one after the other, like:
```Python
from .routers.items import router
from .routers.users import router
```
-The `router` from `users` will overwrite the one form `items` and we won't be able to use them at the same time.
+The `router` from `users` would overwrite the one from `items` and we wouldn't be able to use them at the same time.
-So, to be able to use both of them in the same file, we rename them while importing them using `as`:
+So, to be able to use both of them in the same file, we import the submodules directly:
```Python hl_lines="3 4"
{!./src/bigger_applications/app/main.py!}
@@ -190,18 +190,21 @@ So, to be able to use both of them in the same file, we rename them while import
### Include an `APIRouter`
-Now, let's include the router from the submodule `users`, now in the variable `users_router`:
+Now, let's include the `router` from the submodule `users`:
```Python hl_lines="8"
{!./src/bigger_applications/app/main.py!}
```
+!!! info
+ `users.router` contains the `APIRouter` inside of the file `app/routers/users.py`.
+
With `app.include_router()` we can add an `APIRouter` to the main `FastAPI` application.
It will include all the routes from that router as part of it.
!!! note "Technical Details"
- It will actually internally create a path operation for each path operation that was declared in the `APIRouter`.
+ It will actually internally create a *path operation* for each *path operation* that was declared in the `APIRouter`.
So, behind the scenes, it will actually work as if everything was the same single app.
@@ -216,23 +219,25 @@ It will include all the routes from that router as part of it.
### Include an `APIRouter` with a prefix
-Now, let's include the router form the `items` submodule, now in the variable `items_router`.
+Now, let's include the router form the `items` submodule.
-But, remember that we were lazy and didn't add `/items/` to all the path operations?
+But, remember that we were lazy and didn't add `/items/` nor `tags` to all the *path operations*?
We can add a prefix to all the path operations using the parameter `prefix` of `app.include_router()`.
As the path of each path operation has to start with `/`, like in:
```Python hl_lines="1"
-@router.get("/{item_id}", tags=["items"])
+@router.get("/{item_id}")
async def read_item(item_id: str):
...
```
...the prefix must not include a final `/`.
-So, the prefix in this case would be `/items`:
+So, the prefix in this case would be `/items`.
+
+And we can also add a list of `tags` that will be applied to all the *path operations* included in this router:
```Python hl_lines="9"
{!./src/bigger_applications/app/main.py!}
@@ -245,8 +250,12 @@ The end result is that the item paths are now:
...as we intended.
+And they are marked with a list of tags that contain a single string `"items"`.
+
+These "tags" are especially useful for the automatic interactive documentation systems (using OpenAPI).
+
!!! check
- The `prefix` parameter is (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication.
+ The `prefix` and `tags` parameters are (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication.
!!! tip
@@ -279,6 +288,6 @@ uvicorn app.main:app --reload
And open the docs at http://127.0.0.1:8000/docs.
-You will see the automatic API docs, including the paths from all the submodules:
+You will see the automatic API docs, including the paths from all the submodules, using the correct paths (and prefixes) and the correct tags:
diff --git a/fastapi/applications.py b/fastapi/applications.py
index 980490fbb..6f54df706 100644
--- a/fastapi/applications.py
+++ b/fastapi/applications.py
@@ -176,8 +176,10 @@ class FastAPI(Starlette):
return decorator
- def include_router(self, router: routing.APIRouter, *, prefix: str = "") -> None:
- self.router.include_router(router, prefix=prefix)
+ def include_router(
+ self, router: routing.APIRouter, *, prefix: str = "", tags: List[str] = None
+ ) -> None:
+ self.router.include_router(router, prefix=prefix, tags=tags)
def get(
self,
diff --git a/fastapi/routing.py b/fastapi/routing.py
index b14d7b996..6d252d817 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -237,7 +237,9 @@ class APIRouter(routing.Router):
return decorator
- def include_router(self, router: "APIRouter", *, prefix: str = "") -> None:
+ def include_router(
+ self, router: "APIRouter", *, prefix: str = "", tags: List[str] = None
+ ) -> None:
if prefix:
assert prefix.startswith("/"), "A path prefix must start with '/'"
assert not prefix.endswith(
@@ -250,7 +252,7 @@ class APIRouter(routing.Router):
route.endpoint,
response_model=route.response_model,
status_code=route.status_code,
- tags=route.tags or [],
+ tags=(route.tags or []) + (tags or []),
summary=route.summary,
description=route.description,
response_description=route.response_description,
diff --git a/scripts/lint.sh b/scripts/lint.sh
old mode 100644
new mode 100755