¡Bienvenidos de nuevo a Rustaceo.es! Ahora que hemos aprendido a crear un microservicio en Rust, es hora de agregarle funcionalidades clave para que sea completamente funcional. En esta entrega, implementaremos métodos CRUD, manejo de errores, autenticación y paginación.
🚀 Funcionalidades esenciales en un microservicio #
Para que nuestro microservicio sea completo, debe incluir: ✔ Manejo de datos con operaciones CRUD (Create, Read, Update, Delete). ✔ Autenticación con JWT para proteger los endpoints. ✔ Paginación y filtrado de datos. ✔ Manejo de errores para respuestas más claras. ✔ Logging estructurado para monitoreo.
🏗 Implementando operaciones crud #
Nuestra API permitirá gestionar Pokémon en una base de datos PostgreSQL usando SQLx.
📌 1️⃣ Crear un nuevo pokémon (post) #
use actix_web::{web, HttpResponse, Responder};
use serde::Deserialize;
use sqlx::PgPool;
#[Derive(deserialize)]
struct NuevoElemento {
nombre: String,
tipo: String,
}
async fn agregar_pokemon(pool: web::Data<PgPool>, pokemon: web::Json<NuevoElemento>) -> impl Responder {
let resultado = sqlx::query!("INSERT INTO pokemons (nombre, tipo) VALUES ($1, $2)",
pokemon.nombre, pokemon.tipo)
.execute(pool.get_ref())
.await;
match resultado {
Ok(_) => HttpResponse::Created().finish(),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}
✔ Inserta datos en la base de datos usando SQLx. ✔ Responde con código 201 Created si el Pokémon fue agregado con éxito.
📌 2️⃣ Listar pokémon con paginación (get) #
async fn listar_pokemon(pool: web::Data<PgPool>, params: web::Query<Paginacion>) -> impl Responder {
let offset = params.offset.unwrap_or(0);
let limit = params.limit.unwrap_or(10);
let pokemones = sqlx::query!("SELECT * FROM elementoes LIMIT $1 OFFSET $2", limit, offset)
.fetch_all(pool.get_ref())
.await;
match elementoes {
Ok(elementoes) => HttpResponse::Ok().json(elementoes),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}
✔ Soporta paginación con limit y offset. ✔ Retorna la lista de Pokémon almacenados en la base de datos.
📌 3️⃣ Actualizar un pokémon (put) #
async fn actualizar_elemento(pool: web::Data<PgPool>, id: web::Path<i32>, pokemon: web::Json<NuevoElemento>) -> impl Responder {
let resultado = sqlx::query!("UPDATE elementoes SET nombre = $1, tipo = $2 WHERE id = $3",
pokemon.nombre, pokemon.tipo, id.into_inner())
.execute(pool.get_ref())
.await;
match resultado {
Ok(_) => HttpResponse::Ok().finish(),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}
✔ Actualiza los datos de un Pokémon existente en la base de datos. ✔ Maneja errores en caso de que el Pokémon no exista.
📌 4️⃣ Eliminar un pokémon (delete) #
async fn eliminar_elemento(pool: web::Data<PgPool>, id: web::Path<i32>) -> impl Responder {
let resultado = sqlx::query!("DELETE FROM elementoes WHERE id = $1", id.into_inner())
.execute(pool.get_ref())
.await;
match resultado {
Ok(_) => HttpResponse::NoContent().finish(),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}
✔ Elimina un Pokémon de la base de datos. ✔ Responde con código 204 No Content en caso de éxito.
🔐 Implementando autenticación con jwt #
Para proteger nuestra API, agregamos autenticación con JSON Web Tokens (JWT).
📌 Ejemplo de Generación y Validación de Tokens
use jsonwebtoken::{decode, encode, Header, Validation, EncodingKey, DecodingKey};
use serde::{Serialize, Deserialize};
#[Derive(serialize, deserialize)]
struct Claims {
sub: String,
exp: usize,
}
fn generar_token(usuario: &str) -> String {
let claims = Claims {
sub: usuario.to_string(),
exp: 10000000000,
};
encode(&Header::default(), &claims, &EncodingKey::from_secret("mi_secreto".as_ref())).unwrap()
}
✔ Generación de tokens JWT para autenticación. ✔ Uso de claves secretas para validar los tokens.
🛠 Manejo de errores y logging #
Para mejorar la depuración y monitoreo, usamos tracing para generar logs estructurados.
📌 Ejemplo de Logging con tracing:
use tracing::{info, error};
fn main() {
info!("Microservicio iniciado");
error!("Error crítico detectado");
}
✔ Registro de logs detallados para facilitar la observabilidad. ✔ Integración con Prometheus y Grafana para monitoreo.
🏆 Conclusión #
Hemos agregado funcionalidades clave a nuestro microservicio en Rust:
🎯 Resumen de lo aprendido: ✔ Implementación de operaciones CRUD con SQLx. ✔ Paginación y filtrado en consultas a la base de datos. ✔ Autenticación con JWT para proteger endpoints. ✔ Logging estructurado con tracing para depuración y monitoreo.
🔮 Próximo paso: Desplegar el microservicio en un entorno de producción usando Docker y Kubernetes.
¡Nos vemos en la siguiente entrega, Rustaceos!