Hola amigos en este post les dejo una guía rápida para implementar una API.
Instalar Python
Crear una carpeta del proyecto (Entorno virtual)
Usaremos visual studio code e instalamos la extensión de python
Ejecutamos el siguiente comando en terminal:
python -m venv venv
Luego:
venv\Scripts\actívate
Deberá mostrarse algo similar:

Ejecutamos en la terminal:
pip install fastapi uvicorn
Configurar el intérprete de Python en VS Code
- Presiona Ctrl + Shift + P y busca «Seleccionar intérprete de Python».
- Selecciona el entorno virtual (venv).
Creamos un documento main.py con el siguiente contenido:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def home() :
return "Hola Apolo"
Ejecutamos en terminal con el parámetro reload que detectará cambios automáticamente y no tener que ejecutar el servidor cada rato:
uvicorn main:app --reload
y se mostrará un log con la url y puerto, en mi caso sería:
http://127.0.0.1:8000/
Para cambiar el puerto y hacer accesible desde cualquier disposito de la red podemos hacer lo siguiente con el apoyo de parámetro host y port:
uvicorn main:app --host 0.0.0.0 --port 8080 --reload
La ip será la ip asignada al equipo donde se está ejecutando.
Documentación
Si queremos ver la documentación, esta se genera automáticamente con openapi, ingresando a la siguiente url:
http://127.0.0.1:7777/docs
Y se verá algo así:

Filtrar por parámetros URL
Para cambiar el nombre del texto que default y agrupar por módulos o funcionalidades, añadimos el parámetro tag, y anexamos un ejemplo para regresar un listado de objetos en formato json, el código debería verse así:
personas = [
{
"id" : 1,
"nombre" : "Apolo Miranda"
},
{
"id" : 2,
"nombre" : "Artemisa Miranda"
}
]
from fastapi import FastAPI
app = FastAPI()
@app.get("/", tags=["Home"])
def home() :
return "Hola Apolo bebé"
@app.get("/Personas", tags=["Home"])
def Personas() :
return personas
El resultado:

Para crear un endpoint que reciba un parámetro y busque en nuestro listado:
@app.get("/Personas/{id}", tags=["Home"])
def obtener_persona(id: int):
for persona in personas:
if persona["id"] == id:
return persona
return {"error": "Persona no encontrada"}
y se debería ver algo así:

Filtrar por query string
Añadimos el nuevo método
@app.get("/Personas/", tags=["Home"])
def obtener_persona_por_sexo(sexo: str = None):
if sexo:
filtradas = [persona for persona in personas if persona["sexo"].lower() == sexo.lower()]
if filtradas:
return filtradas
return {"error": f"No se encontraron personas con sexo '{sexo}'"}
return personas # Devuelve toda la lista si no se pasa `sexo`
Y se vería algo asi:

Método post para crear una persona
Aquí mostraré 2 formas de hacerlo, un basándonos en el tipo BaseModel y otro por parámetros y la función Body(), ya que el modelo forza a recibir todas las propiedas y tal vez no queramos recibir el ID ya que este sería generado en el backend
Nuestros imports deben estar así hasta este punto:
from fastapi import FastAPI
from pydantic import BaseModel
from fastapi.params import Body
import random
Definiendo nuestra modelo:
class Persona(BaseModel):
id: int
nombre: str
sexo: str
Definiendo nuestras funciones y algunas validaciones:
@app.post("/Personas", tags=["Home"])
def agregar_persona(persona: Persona):
# Verificar si el ID ya existe
for p in personas:
if p["id"] == persona.id:
raise HTTPException(status_code=400, detail="El ID ya existe")
# Agregar la nueva persona a la lista
## personas.append( persona.dict()) Forma Pydantic v1
personas.append( persona.model_dump()) ## Forma Pydantic v2
return {"mensaje": "Persona agregada con éxito", "persona": nueva_persona}
@app.post("/v2/Personas", tags=["Home"])
def agregar_persona(
nombre: str = Body(),
sexo: str = Body()
):
# Generar un ID único aleatorio
nuevo_id = random.randint(1000, 9999) # ID entre 1000 y 9999
# Verificar que el ID generado no esté duplicado (repetir hasta encontrar uno único)
while any(p["id"] == nuevo_id for p in personas):
nuevo_id = random.randint(1000, 9999)
# Agregar nueva persona
nueva_persona = {"id": nuevo_id, "nombre": nombre, "sexo": sexo}
personas.append(nueva_persona)
return {"mensaje": "Persona agregada con éxito", "persona": nueva_persona}
Ejecutando la primer función con Modelo

Ejecutando la segunda versión con Id autogenerado:

Parámetros obligatorio y opcionales
En los parámetros de la función puedes añadir … en medio de los paréntesis para hacerlo obligatorio, si es opcional solo pon (None)
sexo: str = Body(...)
sexo: str = Body(None)
Parámetros opcionales en modelos
Usando None
class Persona(BaseModel):
id: int | None = None
nombre: str
sexo: str
Usando pydantic
from typing import Optional
class Persona(BaseModel):
id: Optional[int] = None
nombre: str
sexo: str
Lo ideal es crear dos modelos/esquemas, uno para crear, actualizar y otro para mostrar ya que en uno no es requerido el id y en otro si debemos mostrarlo
Método PUT para agregar personas
Agregamos una nueva librería para el manejo de excepciones:
from fastapi import FastAPI, HTTPException
Agregamos el siguiente endpoint:
@app.put("/Personas/{id}", tags=["Personas"])
def actualizar_persona(id: int, nombre: str = Body(...), sexo: str = Body(...)):
for persona in personas:
if persona["id"] == id:
persona["nombre"] = nombre
persona["sexo"] = sexo
return {"mensaje": "Persona actualizada con éxito", "persona": persona}
raise HTTPException(status_code=404, detail="Persona no encontrada")
Método DELETE para eliminar personas
Añadí un ejemplo manipulando la lista y otro usando índices
@app.delete("/Personas/{id}", tags=["Personas"])
def eliminar_persona(id: int):
for persona in personas[:]: # Se usa una copia con `[:]` para evitar problemas al eliminar elementos
if persona["id"] == id:
personas.remove(persona)
return {"mensaje": "Persona eliminada con éxito"}
raise HTTPException(status_code=404, detail="Persona no encontrada")
@app.delete("/v2/Personas/{id}", tags=["Personas"])
def eliminar_persona(id: int):
for index, persona in enumerate(personas):
if persona["id"] == id:
personas.pop(index)
return {"mensaje": "Persona eliminada con éxito"}
raise HTTPException(status_code=404, detail="Persona no encontrada")
Probando los endpoints eliminado 2 y actualizando 1 y posteriormente consultar dichos cambios con el get:

Validaciones de entrada de datos
Nuestras importaciones deberían verse así:
from fastapi import FastAPI, HTTPException, Body
from pydantic import BaseModel, Field
from datetime import datetime
import random
Nuestro modelo añadiendo unas validaciones y añadiendo comentarios de su significado:
class Persona(BaseModel):
id: int | None = None
nombre: str = Field(..., min_length=10, max_length=50) # Validación de nombre
sexo: str
anio_nacimiento: int = Field(None, gt=1900, lt=datetime.now().year) # Año opcional con restricciones
# gt=1900, 'gt' (greater than) significa que debe ser **mayor** a 1900
# ge=1920, 'ge' (greater or equal) significa que debe ser **mayor o igual** a 1920
# lt=datetime.now().year, 'lt' (less than) significa que debe ser **menor** al año actual
# le=datetime.now().year - 1 'le' (less or equal) significa que debe ser **menor o igual** al año anterior
Explicando nuestras referencias
# Importación de FastAPI para crear la aplicación web
from fastapi import FastAPI, HTTPException, Body
# Importaciones de Pydantic para definir modelos de datos y validaciones
from pydantic import BaseModel, Field
# Importación de datetime para trabajar con fechas y obtener el año actual
from datetime import datetime
# Importación de random para generar valores aleatorios, por ejemplo, IDs únicos
import random