Fastapi: Best practice to structure multiple module

Created on 13 Jul 2019  路  8Comments  路  Source: tiangolo/fastapi

When I sperate apis into multiple module, I find it hard to structure the code, currently I approach like this:

# app.py
from fastapi import FastAPI
app = FastAPI()
# api1.py
from app import app

@app.get('/test1')
...
# api2.py
from app import app

@app.get('/test2')
...
# main.py
from app import app
import api1
import api2
$ uvicorn main:app --lifespan on
...

Any suggestions?

question

Most helpful comment

From the FastAPI project-generator codebase:

# app/api/api_v1/endpoints/items.py
...

from fastapi import APIRouter, Depends, HTTPException

...

router = APIRouter()


@router.get("/", response_model=List[Item])
...

```python

app/api/api_v1/api.py

from fastapi import APIRouter

from app.api.api_v1.endpoints import items, login, users, utils

api_router = APIRouter()
api_router.include_router(login.router, tags=["login"])
api_router.include_router(users.router, prefix="/users", tags=["users"])
api_router.include_router(utils.router, prefix="/utils", tags=["utils"])
api_router.include_router(items.router, prefix="/items", tags=["items"])

```python
# app/main.py
from fastapi import FastAPI

...

from app.api.api_v1.api import api_router

...

app = FastAPI(title=config.PROJECT_NAME, openapi_url="/api/v1/openapi.json")

...

app.include_router(api_router, prefix=config.API_V1_STR)

...

All 8 comments

From the FastAPI project-generator codebase:

# app/api/api_v1/endpoints/items.py
...

from fastapi import APIRouter, Depends, HTTPException

...

router = APIRouter()


@router.get("/", response_model=List[Item])
...

```python

app/api/api_v1/api.py

from fastapi import APIRouter

from app.api.api_v1.endpoints import items, login, users, utils

api_router = APIRouter()
api_router.include_router(login.router, tags=["login"])
api_router.include_router(users.router, prefix="/users", tags=["users"])
api_router.include_router(utils.router, prefix="/utils", tags=["utils"])
api_router.include_router(items.router, prefix="/items", tags=["items"])

```python
# app/main.py
from fastapi import FastAPI

...

from app.api.api_v1.api import api_router

...

app = FastAPI(title=config.PROJECT_NAME, openapi_url="/api/v1/openapi.json")

...

app.include_router(api_router, prefix=config.API_V1_STR)

...

Great, thanks!

Thanks @dmontagu! : 馃嵃

@yihuang the docs about that are here: https://fastapi.tiangolo.com/tutorial/bigger-applications/

Hi, guys, I think this is great, thanks. But when using this strategy, It's easy to get 302, why?

For example:
test_client.get("/api/v1/items") # 302
test_client.get("/api/v1/items/") # OK

@markqiu it鈥檚 because you are creating an endpoint with path "/" mounted at ".../items". So the full endpoint path is ".../items/". The 302 is because the system realizes that /items isn鈥檛 a valid endpoint, and you probably meant ".../items/", so it redirects.

If you don鈥檛 want your paths to end in a / (eg if you are using a client library that likes to remove trailing slashes... been there...), make sure you never have paths ending in / in the endpoint decorators (this includes just a single slash).

@dmontagu But If a path includes just a single slash, you can't define the endpoint decorators like this:
@router.get("", response_model=List[Item])

Right, you'd have to give it a name (e.g. @router.get("/items", response_model=List[Item])).

You can mount multiple routers with the same prefix if, for example, you want to have multiple distinct resources with the same prefix and different non-slash-ending endpoints:

from fastapi import FastAPI, APIRouter

app = FastAPI()

router1 = APIRouter()
router2 = APIRouter()


@router1.get("/items")
async def read_items():
    return []


@router2.get("/things")
async def read_things():
    return []


app.include_router(router1, prefix="")
app.include_router(router2, prefix="")

if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host='0.0.0.0', port=8000)

ok, thanks.

Was this page helpful?
0 / 5 - 0 ratings