Una API RESTful construida con FastAPI para la gestión de usuarios, con autenticación basada en JWT, PostgreSQL para el almacenamiento de datos y limitación de velocidad con Redis. Este proyecto proporciona un backend seguro y escalable para el registro de usuarios, la autenticación y las operaciones CRUD.
- User Management: Register, authenticate, and manage users with endpoints for creating, reading, updating, and deleting users.
- JWT Authentication: Secure endpoints with access and refresh tokens, including token renewal.
- Rate Limiting: Configurable request limits (e.g., 3/min for login, 5/min for refresh, 100/hour globally) using Redis.
- PostgreSQL Integration: Persistent storage for user data with UUID-based identifiers.
- CORS Support: Configured for frontend integration (e.g.,
http://localhost:3000). - Custom Error Handling: Consistent error responses for authentication and validation errors.
- Backend: FastAPI, Python 3.13
- Database: PostgreSQL with SQLAlchemy
- Authentication: PyJWT for access and refresh tokens
- Rate Limiting: SlowAPI with Redis
- Dependencies: Pydantic, psycopg2, bcrypt, python-dotenv
- Clone the repository:
git clone <repository-url> cd PyFastApiPg
Asegúrate de que la extensión uuid-ossp esté habilitada en PostgreSQL para la función uuid_generate_v4(). Ejecuta en tu base de datos:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
Asegúrate de tener una base de datos PostgreSQL configurada con el esquema pe y la tabla users creada según el siguiente DDL:
CREATE SCHEMA IF NOT EXISTS pe;
CREATE TABLE IF NOT EXISTS pe.users (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
username VARCHAR(20) NOT null,
password VARCHAR(255) NOT null,
email VARCHAR(150) NOT null,
fullname VARCHAR(255),
level INT DEFAULT 1 NOT null,
active INT DEFAULT 0 NOT NULL,
createdate TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE UNIQUE INDEX users_username_idx ON pe.users (username);
CREATE UNIQUE INDEX users_email_idx ON pe.users (email);
Estos índices únicos en la tabla users (users_username_idx, users_email_idx) aseguran que no se puedan duplicar username ni email.
Instalar y configurar Redis en tu máquina, asegurate de que esté corriendo en localhost:6379 El almacenamiento en memoria es suficiente para desarrollo, pero en producción, usa Redis para soportar múltiples conexiones.
En el archivo app/config/rate_limit.py está la configuración de Redis y se puede optar por no usarlo cambiando la configuración a solo Memoria.
Instala Python 3.13 en tu sistema. Virtualenv (opcional pero recomendado): Para crear un entorno virtual.
Crea un directorio para el proyecto y un entorno virtual:
mkdir PyFastApiPg (Crea la carpeta si ya no existe)
cd PyFastApiPg
python -m venv venv
source venv/bin/activate # En Windows: venv\Scripts\activate
Crea el archivo requirements.txt con las dependencias necesarias:
fastapi
uvicorn
psycopg2-binary
pydantic
python-dotenv
uuid
SQLAlchemy
email-validator
PyJWT
passlib
bcrypt
slowapi
redis
Instala las dependencias:
pip install -r requirements.txt
Crea el archivo .env en la raíz del proyecto para las variables de entorno:
DATABASE_URL=postgresql://username:password@localhost:5432/your_database
SECRET_KEY=your-secret-key-for-jwt
REFRESH_SECRET_KEY=your-refresh-secret-key-for-jwt
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=7
Reemplaza username, password, localhost, 5432 y your_database con los valores correspondientes de tu base de datos PostgreSQL. También tu secret-key-for-jwt para los Token.
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── config/
│ │ ├── __init__.py
│ │ ├── database.py
│ │ ├── rate_limit.py
│ │ └── security.py
│ ├── models/
│ │ ├── __init__.py
│ │ └── user.py
│ ├── controllers/
│ │ ├── __init__.py
│ │ └── user_controller.py
│ ├── schemas/
│ │ ├── __init__.py
│ │ └── user_schema.py
│ └── services/
│ ├── __init__.py
│ └── user_service.py
├── requirements.txt
└── .env
Los archivos init.py deben quedar vacíos.
Los orígenes permitidos (http://localhost:3000, https://tu-dominio.com) son ejemplos. Ajusta la lista origins en main.py según los dominios de tu frontend. Por ejemplo, si tu frontend corre en http://localhost:5173 (común con Vite), cámbialo:
origins = [
"http://localhost:5173",
"https://tu-dominio.com",
]
Para desarrollo, puedes usar origins=["*"], pero evítalo en producción por seguridad.
La arquitectura MVC está implementada de la siguiente manera: Modelo: app/models/user.py (SQLAlchemy para interactuar con la base de datos).
Vista: Los esquemas Pydantic en app/schemas/user_schema.py para validación y serialización.
Controlador: app/controllers/user_controller.py para manejar las rutas HTTP.
Servicio: app/services/user_service.py para la lógica de negocio.
Este proyecto es un ejemplo funcional y completo que te permitirá aprender a usar FastAPI y PostgreSQL en Python.
uvicorn app.main:app --reload
Esto ejecutará la aplicación en http://127.0.0.1:8000.
Accede a la documentación interactiva de la API en: Swagger UI: http://127.0.0.1:8000/docs
POST http://127.0.0.1:8000/api/v1/users/login
Content-Type: application/json
body:
{
"username": "testuser",
"password": "securepass"
}
Respuesta esperada:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
Este endpoint no requiere validación de token y lo puedes usar para crear tu primer usuario.
POST http://127.0.0.1:8000/api/v1/users/register
Content-Type: application/json
body:
{
"username": "testuser1",
"password": "securepass",
"email": "test1@example.com",
"fullname": "Test User 1",
"level": 1,
"active": 1
}
Usa el access_token en el encabezado Authorization como Bearer <access_token>. Por ejemplo:
GET http://127.0.0.1:8000/api/v1/users/
Authorization: Bearer <access_token>
POST http://127.0.0.1:8000/api/v1/users/refresh
Content-Type: application/json
body:
{
"refresh_token": "<refresh_token>"
}
POST http://127.0.0.1:8000/api/v1/users
Content-Type: application/json
body:
{
"username": "testuser",
"password": "securepass",
"email": "test@example.com",
"fullname": "Test User",
"level": 1,
"active": 1
}
GET http://127.0.0.1:8000/api/v1/users
GET http://127.0.0.1:8000/api/v1/users/{uuid_del_usuario}
PATCH http://127.0.0.1:8000/api/v1/users/{uuid_del_usuario}
Content-Type: application/json
body:
{
"username": "newusername",
"email": "newemail@example.com"
}
DELETE http://127.0.0.1:8000/api/v1/users/{uuid_del_usuario}