Rust y API: de REST a gRPC — escribiendo rápido y seguro

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué Rust es el candidato ideal para trabajar con API?

\n\n

Si todavía piensas que Rust es solo para programación de sistemas y reemplazar C++, estás muy atrasado con la realidad. Rust ha irrumpido con fuerza en el mundo del desarrollo web y los servicios backend. Y no solo ha irrumpido, sino que ha ocupado un nicho donde son importantes la velocidad, la fiabilidad y la seguridad de la memoria.

\n\n

Pero seamos honestos: trabajar con API en Rust no es solo "tomar una biblioteca lista y olvidarse". Es un arte de equilibrio entre el poder del lenguaje y la facilidad de desarrollo. En este artículo analizaremos tres enfoques principales: REST, GraphQL y gRPC. Cada uno es bueno a su manera, y la elección depende de tu tarea. ¡Allá vamos!

\n\n

REST en Rust: un clásico que funciona

\n\n

REST sigue siendo el estilo de API más popular. Es simple, intuitivo y compatible con prácticamente todo. Para Rust hay varios frameworks excelentes, pero el rey aquí es actix-web. Es rápido, asíncrono y con un ecosistema excelente.

\n\n

Escribiendo un servicio REST simple con actix-web

\n\n

Vamos a crear un miniservicio para gestionar una lista de tareas (todo). Necesitaremos actix-web, serde para la serialización y tokio como runtime asíncrono.

\n\n
// Cargo.toml\n// [dependencies]\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n// serde_json = "1"\n// tokio = { version = "1", features = ["full"] }\n\nuse actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};\nuse serde::{Deserialize, Serialize};\nuse std::sync::Mutex;\n\n#[derive(Serialize, Deserialize, Clone)]\nstruct Task {\n    id: u32,\n    title: String,\n    completed: bool,\n}\n\nstruct AppState {\n    tasks: Mutex<Vec<Task>>,\n}\n\n#[get("/tasks")]\nasync fn get_tasks(data: web::Data<AppState>) -> impl Responder {\n    let tasks = data.tasks.lock().unwrap();\n    HttpResponse::Ok().json(tasks.clone())\n}\n\n#[post("/tasks")]\nasync fn create_task(data: web::Data<AppState>, body: web::Json<Task>) -> impl Responder {\n    let mut tasks = data.tasks.lock().unwrap();\n    let new_id = tasks.len() as u32 + 1;\n    let task = Task {\n        id: new_id,\n        title: body.title.clone(),\n        completed: false,\n    };\n    tasks.push(task.clone());\n    HttpResponse::Created().json(task)\n}\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n    let state = web::Data::new(AppState {\n        tasks: Mutex::new(vec![]),\n    });\n\n    HttpServer::new(move || {\n        App::new()\n            .app_data(state.clone())\n            .service(get_tasks)\n            .service(create_task)\n    })\n    .bind("127.0.0.1:8080")?\n    .run()\n    .await\n}\n
\n\n

La belleza de este código es que es seguro en cuanto a memoria y no requiere un recolector de basura. actix-web procesa miles de solicitudes por segundo en un solo hilo, utilizando los mecanismos asíncronos de Rust. Intenta ejecutarlo: te sorprenderá lo rápido que es incluso en hardware modesto.

\n\n

¿Cuándo no es REST la mejor opción?

\n\n

REST es excelente para operaciones CRUD, pero si necesitas consultar datos de forma flexible (por ejemplo, recursos anidados), REST comienza a requerir múltiples endpoints. Aquí es donde entra en escena GraphQL.

\n\n

GraphQL en Rust: flexibilidad sin dolor

\n\n

GraphQL permite al cliente solicitar exactamente los datos que necesita. Para Rust, la mejor opción es async-graphql. Se integra estrechamente con actix-web y proporciona un potente DSL para describir esquemas.

\n\n

Ejemplo: API para una biblioteca de libros

\n\n

Supongamos que queremos dar a los clientes la posibilidad de consultar libros y autores. Con GraphQL esto se hace con un solo esquema.

\n\n
// Cargo.toml\n// [dependencies]\n// async-graphql = "7"\n// async-graphql-actix-web = "7"\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n\nuse async_graphql::{Context, EmptyMutatio                

Blogs

Book Recommendations