¡Bienvenidos de nuevo a Rustaceo.es! En esta serie, construiremos una API REST en Rust desde cero, utilizando Actix-Web para manejar solicitudes HTTP de manera eficiente. Esta primera parte se enfocará en el diseño inicial de la API, la creación de rutas y la estructura básica sin almacenamiento en base de datos.
🚀 Objetivos de la api #
Nuestra API tendrá las siguientes características iniciales:
- Manejo de Pokémon: Permitirá registrar, listar y obtener información sobre Pokémon.
- Rutas y Endpoints básicos: Implementaremos rutas para operaciones CRUD básicas.
- Uso de Actix-Web: Un framework rápido y eficiente para Rust.
En esta primera fase, dejaremos de lado SQL o persistencia avanzada para centrarnos en la estructura básica de la API.
🛠 Retos a superar #
Antes de empezar, identifiquemos los principales desafíos que enfrentaremos: ✔ Definir una estructura clara para nuestros datos. ✔ Manejar peticiones HTTP y responder con datos JSON. ✔ Implementar una API escalable sin depender aún de una base de datos.
📂 Configuración del proyecto #
Empezamos creando un nuevo proyecto en Rust con Actix-Web:
cargo new rest-api-pokemon --bin
cd rest-api-pokemon
Ahora agregamos las dependencias en Cargo.toml
:
[dependencies]
actix-web = "4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Ejecutamos cargo check
para asegurarnos de que todo está en orden.
🌐 Implementando el servidor con actix-web #
Definimos la estructura base de nuestro servidor y creamos un endpoint básico.
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
async fn bienvenida() -> impl Responder {
HttpResponse::Ok().body("¡Bienvenido a la API de Pokémon en Rust!")
}
#[Actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(bienvenida))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Ejecutamos el servidor con:
cargo run
Accedemos a http://127.0.0.1:8080/
y veremos nuestro mensaje de bienvenida.
🏗 Creando rutas para pokémon #
Ahora definimos nuestra estructura Pokémon
y añadimos rutas para manejar Pokémon.
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
#[Derive(serialize, deserialize)]
struct Pokémon {
id: usize,
nombre: String,
tipo: String,
}
struct AppState {
elementoes: Mutex<Vec<Pokémon>>,
}
async fn listar_elemento(data: web::Data<AppState>) -> impl Responder {
let elementoes = data.elementoes.lock().unwrap();
HttpResponse::Ok().json(&*elementoes)
}
async fn agregar_elemento(data: web::Data<AppState>, nuevo_elemento: web::Json<Pokémon>) -> impl Responder {
let mut elementoes = data.elementoes.lock().unwrap();
elementoes.push(nuevo_elemento.into_inner());
HttpResponse::Created().finish()
}
#[Actix_web::main]
async fn main() -> std::io::Result<()> {
let data = web::Data::new(AppState {
elementoes: Mutex::new(vec![]),
});
HttpServer::new(move || {
App::new()
.app_data(data.clone())
.route("/elementoes", web::get().to(listar_elemento))
.route("/elementoes", web::post().to(agregar_elemento))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
✔ /elementoes
(GET): Lista todos los Pokémon. ✔ /elementoes
(POST): Agrega un nuevo Pokémon. ✔ Datos almacenados temporalmente en memoria con Mutex<Vec<Pokémon>>
.
📌 Conclusión #
Hemos creado la primera versión de nuestra API REST en Rust con Actix-Web.
🎯 Resumen de lo aprendido: ✔ Configuración de un servidor con Actix-Web. ✔ Creación de rutas y manejo de JSON con serde
. ✔ Uso de Mutex
para almacenamiento en memoria.
🔮 Próximo paso: En la segunda parte, implementaremos persistencia con SQLx para almacenar Pokémon en una base de datos.
¡Nos vemos en la siguiente entrega, Rustaceos!