6

APIRouter para modularización del proyecto

Durante el desarrollo de este curso habrás notado que todo el código se escribió en el archivo main.py. Esto puede funcionar bien cuando tienes uno o dos modelos, pero ¿qué pasa si tu aplicación empieza a crecer tanto y se apila todo en un archivo? Bueno, para eso FastAPI tiene una clase llamada APIRouter que, básicamente crea apps dentro de la app principal para agrupar las path operations y hacer más escalable y legible tu código.

Estructura de carpetas y archivos

Para seguir el tutorial del curso, yo llamé mi aplicación TrinosAPI y definí la siguiente estructura de carpetas, siguiendo las recomendaciones en la documentación de FastAPI:

|--- trinos-api
||--- __init__.py
||--- main.py
||--- models
|||--- __init__.py
|||--- user.py
|||--- trino.py
||
||--- paths
|||--- __init__.py
|||--- user.py
|||--- trino.py
||
||--- data
|||--- users.json
|||--- trinos.json
||
||--- .gitignore
||--- requirements.txt

Modelos

User

En el archivo models/user.py se importan las librerías requeridas y se definen las clases de la entidad User, tal como indicó el profe Facundo en la clase respectiva. Mis diferencias son:

  1. Implementé un campo username para usar como nombre del usuario al hacer login en la aplicación.

  2. En lugar de nombrar la clase UserRegister la llamé UserFull, por ser la clase que contiene todos los campos solicitados en el formulario de registro. Para crearla aproveché el concepto de herencia múltiple que permite Pydantic en los modelos de esta forma:

...
classUserFull(User,UserLogin):
	pass

Trino

En trino.py nuevamente se importan las librerías requeridas para crear la clase Trino tal como se definió en la clase. Para poder agregar el campo by se debe importar la clase User desde el módulo user.py. En mi caso, importé la clase UserBase porque considero que no es necesario guardar la fecha de nacimiento del usuario en cada trino:

#Python packagesfrom datetime import datetime
from typing import Optional
from uuid import UUID
#Pydantic packagesfrom pydantic import BaseModel
from pydantic import Field
#Local packagesfrom models.user import UserBase

#Class for Trino ModelclassTrino(BaseModel):
    id: UUID = Field(
        ...,
        title="Trino Id"
        )
    content: str = Field(
        ...,
        title="Trino content",
        min_length=1,
        max_length=256
        )
    created_at: datetime = Field(
        default=datetime.now(),
    )
    updated_at: Optional[datetime] = Field(
        default=datetime.now(),
    )
    by: UserBase = Field(
        ...,
        title="User who created the trino"
        )

Paths

User

Para las path operations de la clase User se crea el archivo paths/user.py.
Aquí la diferencia respecto a lo visto en clase es el uso de APIRouter. En lugar de cargar las path operations directamente a la app con el decorador @app, lo que se hace es crear un objeto de la clase APIPRouter y decorar las path functions con este objeto. Recuerda además importar los modelos desde el módulo respectivo:

#Python packagesfrom typing import List
import json
#FastAPI packagesfrom fastapi import APIRouter
from fastapi import status
from fastapi import Body
#Local packagesfrom models.user import User, UserFull

router = APIRouter()

@router.post(
    path="/signup",
    response_model=User,
    status_code=status.HTTP_201_CREATED,
    summary="Sign up a new user",
    tags=["User"]
)
defsignup(
    user: UserFull = Body(
        ...,
    )
):
...

Trino

Repetimos lo mismo con paths/trino.py:

#Python packagesfrom typing importListimport json

#FastAPI packagesfrom fastapi import APIRouter
from fastapi import status

#Local packagesfrom models.trino import Trino

router = APIRouter()

#Path operations to home page
@router.get(
    path="/",
    response_model=List[Trino],
    status_code=status.HTTP_200_OK,
    summary="Get all trinos",
    tags=["Home","Trino"]
    )
defhome():
...

main

Finalmente debemos llevar las paths operations a la aplicación principal. Para ello importamos los objetos router de cada archivo de paths y los añadimos al objeto app:

#Python packages#Pydantic packages#FastAPI packagesfrom fastapi import FastAPI

#Local packagesfrom paths import user, trino

app = FastAPI()

#Includes the paths from paths folder
app.include_router(user.router)
app.include_router(trino.router)

Y ya está, de esta forma logramos separar los modelos y endpoints de manera que la aplicación sea más clara y escalable.

Tal vez exista una forma más profesional de realizar esta tarea, ojalá que el próximo curso de esta saga nos aclare este proceso.

Si quieres ver como estoy desarrollando esta aplicación (a la fecha de este tutorial aún me faltan las otras path functions) puedes entrar a mi repositorio de GitHub (https://github.com/JosueLC/trinos-api/)

Escribe tu comentario
+ 2