---
# System prepended metadata

title: Estructura de projecte FastAPI
tags: ['#M13 PROJECTE']

---

# Estructura de projecte FastAPI

D'acord al que s'especifica a la documentació oficial de FastAPI ([Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/)), a mesura que les funcionalitats que ha de cobrir la nostra API creixen cal separar els components en diferents arxius. 

D'aquesta forma es guanya modularitat i flexibilitat, ja que afegir un endpoint nou és tant senzill com afegir un arxiu .py i no modificar el main (on fins ara teníem totes les nostres rutes/endpoints).

#### Estructura de carpetes

S'aconsella distribuir els components d'aquesta forma:

```
.
├── app                  # "app" és un paquet Python
│   ├── __init__.py      # aquest arxiu converteix "app" en un paquet python
│   ├── main.py          # mòdul "main", p.ex. import app.main
│   ├── dependencies.py  # mòdul de dependències, p.ex import app.dependencies
│   └── routers          # "routers" és un subpaquet Python 
│   │   ├── __init__.py  # converteix "routers" en un subpaquet Python
│   │   ├── items.py     # submòdul "items", el qual conté endpoints
d'ítems, p.ex import app.routers.items
│   │   └── users.py     # submòdul "users", el qual conté endpoints
d'ítems, p.ex import app.routers.users
│   └── internal         # "internal" és un subpaquet Python 
│       ├── __init__.py  # converteix "internal" en un subpaquet Python
│       └── admin.py     # submòdul "admin", p.ex import app.internal.admin 
```

Observeu que es fa necessari afegir arxius `__init.py__` dins cada carpeta per tal de permetre la importació del codi contingut en un arxiu .py dins un altre. Aquests arxius no necessàriament contenen cap línia de codi, per tant es crearan buits.

Cada subpaquet d'aquests juga un rol, però a grans trets:

* routers conté els endpoints. 
* internal conté la connexió a la base de dades (si n'hi ha) i aquells mètodes que fan les operacions DML per recuperar i mantenir els registres de la base de dades (és a dir, selects, inserts, etc.).

Pel que fa a dependencies, és un arxiu on podem ficar aquelles dependències utilitzades en múltiples llocs del codi. Un exemple d'ús:

```
from typing import Annotated

from fastapi import Header, HTTPException


async def get_token_header(x_token: Annotated[str, Header()]):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")


async def get_query_token(token: str):
    if token != "jessica":
        raise HTTPException(status_code=400, detail="No Jessica token provided")
```

En aquest supòsit, els altres mòduls .py importarien de dependencies el mètode necessari.

#### Procediment amb un exemple

Agafarem el codi de l'API d'exemple i anem a adaptar-lo a aquesta estructura.

Deixem l'estructura de carpetes com segueix:

![image](https://hackmd.io/_uploads/HkCEHcMyyl.png)

En aquest cas, el subpaquet internal no conté cap arxiu i dependencies el deixarem buit.

Així el codi s'ha de refer com segueix. Comencem pels endpoints continguts a routers:

Codi d'items.py

```
from typing import Union

from fastapi import APIRouter

router = APIRouter()

@router.get("/items/{item_id}",tags=["items"])
def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}
```

Fixeu-vos alguns detalls:

* Importem APIRouter.
* Fem un @router.get on especifiquem:
    * La ruta per accedir a l'endpoint, és a dir, "/items/{item_id}"
    * Una etiqueta a tags, que ha de dur el mateix nom que el mòdul/submòdul. En aquest cas, al ser items.py, tags=["items"]

Farem el mateix si hi ha més rutes i endpoints, afegint nous submòduls i seguint aquest procés.

Codi de main.py

En aquest cas per il·lustrar el funcionament hem deixat sols el codi de l'arrel (l'app.get("/")), però es podria moure a l'items.py o a qualsevol altre submòdul dins routers.

Després cal fer l'import dels submòduls definits a routers. En aquest cas fem "from app.routers import items". I lligat a aquest import tenim la instrucció **app.include_router**, on hem de fer l'include del submòdul del qual volem importar/utilitzar el seu codi. En aquest cas es tracta d'items.router.

```
from fastapi import FastAPI

from app.routers import items

app = FastAPI()

app.include_router(items.router)

@app.get("/")
def read_root():
    return {"Hello": "World"}
```

#### **Forma d'arrencar l'API**

Cal posicionar-se a l'arrel, és a dir, a la carpeta que conté el paquet app i fer "python3 -m uvicorn app.main:app --reload". Fixeu-vos que a diferència del primer tutorial, aquest cop escrivim app.main:app i no main:app, ja que estem dient que main està contingut al paquet app.

En aquest exemple, FastAPI és la carpeta arrel que conté la carpeta app i des d'on arrencarem l'API.

```
PS C:\Users\antot\OneDrive\Documentos\sample1\FastAPI> python3 -m uvicorn app.main:app --reload
INFO:     Will watch for changes in these directories: ['C:\\Users\\antot\\OneDrive\\Documentos\\sample1\\FastAPI']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [40704] using WatchFiles
INFO:     Started server process [28656]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
```