API RESTful: FAST API

Sitio: Campus virtual DAW - damiansu
Curso: Programación en Python
Libro: API RESTful: FAST API
Imprimido por: Invitado
Día: jueves, 22 de enero de 2026, 04:40

1. Explicación

.

2. FastAPI básico + Swagger

Proyecto: fastapi-demo

Abrimos el proyecto y activamos el entorno virtual

python -m venv venv

Windows

 .\venv\Scripts\Activate.ps1

Mac

source venv/bin/activate

Instalamos dependencias

pip install fastapi uvicorn

2.1. main.py

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI(
    title="Demo FastAPI (sin BD)",
    description="Primero Swagger, luego MySQL",
    version="1.0.0"
)

class ProductoCreate(BaseModel):
    nombre: str = Field(min_length=1, max_length=100)
    precio: float = Field(gt=0)
    stock: int = Field(ge=0, default=0)

@app.get("/")
def root():
    return {"ok": True, "mensaje": "FastAPI funcionando"}

@app.post("/productos")
def crear_producto(producto: ProductoCreate):
    # Simulación: devolvemos lo recibido + un id fijo
    return {"id": 1, **producto.model_dump()}

2.2. Arrancamos el server

uvicorn main:app --reload

Verificamos:

  • http://localhost:8000

  • http://localhost:8000/docs

Lanzamos un POST a /productos

Provocamos un 200 y un 422

3. Conectar con MySQL

.

3.1. Levantamos el servicio

Levantamos el servicio de MySQL

  • puerto: 3307
  • usuario: root
  • contraseña: ChuckNorris2025

Los datos a importar son estos;

CREATE DATABASE IF NOT EXISTS fastapi_db
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

USE fastapi_db;

DROP TABLE IF EXISTS productos;

CREATE TABLE productos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    precio DECIMAL(10,2) NOT NULL,
    stock INT NOT NULL DEFAULT 0
);

INSERT INTO productos (nombre, precio, stock) VALUES
('Portátil Lenovo', 899.99, 10),
('Monitor LG 27', 249.50, 15),
('Teclado Mecánico', 79.99, 30);

3.2. db.py

Instalamos dependencias

pip install sqlalchemy pymysql

Creamos db.py, cambiar valores:

  • puerto: 3307
  • usuario: root
  • contraseña: ChuckNorris2025
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

DATABASE_URL = "mysql+pymysql://root:ChuckNorris2025@localhost:3307/fastapi_db"

engine = create_engine(DATABASE_URL, echo=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

3.3. models.py

Creamos los modelos de las tablas, models.py

from sqlalchemy import Column, Integer, String, Numeric
from db import Base

class Producto(Base):
    __tablename__ = "productos"

    id = Column(Integer, primary_key=True, index=True)
    nombre = Column(String(100), nullable=False)
    precio = Column(Numeric(10, 2), nullable=False)
    stock = Column(Integer, nullable=False, default=0)

3.4. main.py (modificación)

Modificamos main.py

from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session

from db import get_db
from models import Producto

app = FastAPI(
    title="FastAPI + Swagger + MySQL",
    description="Sesión práctica: primero Swagger y luego persistencia real",
    version="2.0.0"
)

class ProductoCreate(BaseModel):
    nombre: str = Field(min_length=1, max_length=100)
    precio: float = Field(gt=0)
    stock: int = Field(ge=0, default=0)

class ProductoResponse(ProductoCreate):
    id: int
    class Config:
        from_attributes = True  # Pydantic v2

@app.get("/")
def root():
    return {"ok": True, "mensaje": "API con MySQL lista. Ve a /docs"}

@app.get("/productos", response_model=list[ProductoResponse])
def listar_productos(db: Session = Depends(get_db)):
    return db.query(Producto).all()

@app.get("/productos/{producto_id}", response_model=ProductoResponse)
def obtener_producto(producto_id: int, db: Session = Depends(get_db)):
    prod = db.query(Producto).filter(Producto.id == producto_id).first()
    if not prod:
        raise HTTPException(status_code=404, detail="Producto no encontrado")
    return prod

@app.post("/productos", response_model=ProductoResponse, status_code=201)
def crear_producto(producto: ProductoCreate, db: Session = Depends(get_db)):
    nuevo = Producto(nombre=producto.nombre, precio=producto.precio, stock=producto.stock)
    db.add(nuevo)
    db.commit()
    db.refresh(nuevo)
    return nuevo

3.5. Verificamos

Verificamos los métodos y comprobamos que el POST cambia el estado del  base de datos:

Primeras conclusiones

  • Primero: API y documentación (Swagger)

  • Segundo: persistencia real (MySQL + ORM)

  • FastAPI no crea la BD: se integra con el ORM (como JPA en Java)