Docs Menu
Docs Home
/ /

Integrar MongoDB con Actix

Esta guía muestra cómo crear una aplicación web con Actix Web y MongoDB. Actix es un potente framework web asíncrono para Rust que facilita la creación de servicios HTTP rápidos y con seguridad de tipos.

La aplicación de este tutorial consta de las siguientes capas:

  • Capa de base de datos: MongoDB (alojada en MongoDB Atlas) almacena y recupera datos.

  • Capa de servidor: Actix Web proporciona el servidor HTTP, enrutamiento y endpoints API para conectar tu frontend a tu base de datos MongoDB.

  • Capa de gestión de datos: el sistema de tipos de Rust y async/await proporcionan un manejo seguro de datos con garantías en tiempo de compilación.

  • Capa de presentación: las páginas HTML renderizadas por el servidor, diseñadas con Tailwind CSS, muestran los datos del restaurante de muestra en una tabla.

Construirás una pequeña aplicación que:

  • Se conecta a un clúster MongoDB Atlas que contiene el sample_restaurants dataset

  • Expone un endpoint /restaurants que lista todos los restaurantes

  • Expone un punto final /browse que enumera los restaurantes en Queens con "Moon" en el nombre

  • Renderiza los resultados como una tabla HTML con una barra de navegación compartida.

El modelo de documentos flexible de MongoDB almacena datos como documentos tipo BSON/JSON. Esto funciona de forma natural con las estructuras de Rust que modelan tus datos, sin complejas capas ORM ni migraciones de esquemas.

Cuando combina Actix Web y el controlador asincrónico MongoDB Rust, esta pila proporciona:

  • Estructuras de datos flexibles que pueden evolucionar sin migraciones costosas

  • E/S asincrónica y sin bloqueo para API de alto rendimiento y alta concurrencia

  • Seguridad de tipos fuerte desde la capa de base de datos hasta tus manejadores y modelos

  • Integración sencilla con vistas web (plantillas HTML o creación manual de cadenas, como en este tutorial)

Esta combinación funciona para aplicaciones que requieren lo siguiente:

  • Esquemas en evolución a lo largo del tiempo

  • Alto rendimiento y concurrencia

  • Fuertes garantías de tiempo de compilación sobre las formas de datos

Este tutorial te guía para desarrollar una aplicación Actix Web que se integra con MongoDB. La aplicación accede a datos de ejemplo de restaurantes en un clúster de MongoDB Atlas y muestra los resultados en tu navegador.

Tip

Si prefiere conectarse a MongoDB utilizando el controlador Rust sin Actix Web, consulte la Guíade inicio rápido del controlador Rust.

Siga los pasos de esta sección para instalar los requisitos previos, crear un clúster MongoDB Atlas y estructurar el proyecto Rust.

1

Para crear la aplicación de inicio rápido, asegúrese de tener instalado lo siguiente:

Requisito previo
notas

Rust

Editor de código

Este tutorial utiliza Visual Studio Code con la extensión Rust, pero puedes usar el editor que prefieras.

Terminal

Usa Terminal o una aplicación similar para macOS. Usa PowerShell para Windows.

2

MongoDB Atlas es un servicio de base de datos en la nube totalmente administrado que aloja sus implementaciones de MongoDB. Si no tiene una implementación de MongoDB, cree un clúster de MongoDB gratis (no se requiere tarjeta de crédito) completando el tutorial de introducción a MongoDB. Este tutorial también muestra cómo cargar conjuntos de datos de muestra en su clúster, incluyendo la sample_restaurants base de datos que utiliza este tutorial.

Importante

Asegúrese de tener el conjunto de datos sample_restaurants cargado en su clúster antes de continuar. Si falta el conjunto de datos sample_restaurants, las listas de restaurantes en sus páginas de muestra estarán vacías.

Para conectarse a su clúster de MongoDB, use una URI de conexión. Para saber cómo recuperarla, consulte la sección "Añadir la cadena de conexión" del tutorial "Introducción a MongoDB".

Tip

Guarda la URI de tu conexión en un lugar seguro. La añadirás a un archivo .env más adelante.

3

Ejecute el siguiente comando en su terminal para crear un nuevo proyecto Rust:

cargo new actix-quickstart
cd actix-quickstart

Este comando crea un nuevo proyecto Rust llamado actix-quickstart y navega al directorio del proyecto.

4

Abra Cargo.toml y reemplace la sección [dependencies] con lo siguiente:

inicio rápido de actix/Cargo.toml
[package]
name = "actix_quickstart"
version = "0.1.0"
edition = "2024"
[dependencies]
actix-web = "4"
actix-files = "0.6"
actix-cors = "0.7"
mongodb = "3.4.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
dotenv = "0.15"
futures = "0.3"

Instale las nuevas dependencias ejecutando el siguiente comando en su terminal:

cargo build

Estas dependencias proporcionan:

  • actix-web:Servidor HTTP, enrutamiento y tipos de solicitud/respuesta.

  • mongodb:Controlador MongoDB asíncrono oficial para Rust.

  • tokio:Tiempo de ejecución asíncrono utilizado por Actix Web y el controlador MongoDB.

  • serde / serde_json: Serialización y deserialización de datos JSON y BSON.

  • dotenv:Carga variables de entorno desde un archivo .env para desarrollo local.

  • futures:Utilidades para trabajar con transmisiones asíncronas (utilizadas para cursores MongoDB).

Después de configurar el proyecto, siga los pasos de esta sección para configurar las variables de entorno, configurar su conexión MongoDB, definir su modelo de datos e implementar los servicios de consulta de base de datos.

1

Cree un archivo .env en la raíz de su proyecto para almacenar su URI de conexión MongoDB.

Ejecute el siguiente comando en la raíz de su proyecto:

touch .env

Abra .env y agregue su URI de conexión y número de puerto:

MONGO_URI="<your-mongodb-connection-uri>"
PORT=5050

Reemplace <your-mongodb-connection-uri> con la URI de conexión que guardó anteriormente.

2

Cree un nuevo archivo llamado db.rs en el directorio src para administrar la conexión MongoDB.

Ejecute el siguiente comando en la raíz de su proyecto:

touch src/db.rs

Abra db.rs y agregue el siguiente código para configurar la conexión de la base de datos y el cliente MongoDB:

inicio rápido de actix/src/db.rs
use mongodb::{options::ClientOptions, Client, Database};
pub async fn init_db(mongo_uri: &str) -> Database {
let mut client_options = ClientOptions::parse(mongo_uri)
.await
.expect("Failed to parse MongoDB connection string");
client_options.app_name = Some("actix_quickstart".to_string());
let client = Client::with_options(client_options)
.expect("Failed to initialize MongoDB client");
client.database("sample_restaurants")
}

Este módulo:

  • Analiza la cadena de conexión de MongoDB de su entorno.

  • Configura el nombre de la aplicación del controlador para facilitar su observación.

  • Crea un cliente y devuelve un identificador de base de datos para la base de datos sample_restaurants.

3

Cree un nuevo archivo llamado models.rs en el directorio src para definir el modelo de datos del restaurante.

Ejecute el siguiente comando en la raíz de su proyecto:

touch src/models.rs

Abra models.rs y agregue el siguiente código para definir la estructura Restaurante:

inicio rápido de actix/src/modelos.rs
use mongodb::bson::oid::ObjectId;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct RestaurantRow{
pub name: Option<String>,
pub borough: Option<String>,
pub cuisine: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<ObjectId>,
}

Esta estructura representa un documento de restaurante en la colección MongoDB. Utiliza anotaciones Serde para asignar campos BSON a campos de estructura Rust.

4

Cree un módulo de servicio que aísle la lógica de consulta de MongoDB de los controladores HTTP.

Ejecute los siguientes comandos en la raíz de su proyecto:

mkdir -p src/services
touch src/services/restaurant_queries.rs

Abre restaurant_queries.rs y añade el siguiente código:

actix-quickstart/src/servicios/restaurant_queries.rs
use futures::stream::TryStreamExt;
use mongodb::{
bson::doc,
Collection,
};
use crate::models::RestaurantRow;
pub async fn fetch_all(restaurants: &Collection<RestaurantRow>) -> Result<Vec<RestaurantRow>, mongodb::error::Error> {
let cursor = restaurants
.find(doc! {})
.projection(doc! {
"name": 1,
"borough": 1,
"cuisine": 1,
"_id": 1,
})
.await?;
cursor.try_collect().await
}
pub async fn fetch_by_borough(
restaurants: &Collection<RestaurantRow>,
borough: &str,
name: &str,
) -> Result<Vec<RestaurantRow>, mongodb::error::Error> {
let filter = doc! {
"borough": borough,
"name": { "$regex": name, "$options": "i" }
};
let cursor = restaurants
.find(filter)
.projection(doc! {
"name": 1,
"borough": 1,
"cuisine": 1,
"_id": 1,
})
.await?;
cursor.try_collect().await
}

Este archivo contiene dos funciones asincrónicas:

  • fetch_all():Devuelve todos los restaurantes con una proyección de campo.

  • fetch_by_borough():Devuelve restaurantes filtrados por distrito y por una expresión regular de nombre que no distingue entre mayúsculas y minúsculas.

Ambas funciones devuelven Vec<RestaurantRow>, por lo que su capa de presentación no necesita lidiar con BSON sin procesar.

5

Ejecute el siguiente comando en la raíz de su proyecto:

touch src/services/mod.rs

Abra mod.rs y agregue el siguiente código para exportar el módulo restaurant_queries:

inicio rápido de actix/src/servicios/mod.rs
pub mod restaurant_queries;

Ahora que las capas de base de datos y de servicio están en su lugar, configure Actix Web para:

  • Inicialice la conexión de MongoDB

  • Definir el estado de la aplicación compartida

  • Exponer los puntos finales /restaurants y /browse

  • Renderizar páginas HTML con Tailwind CSS

1

Cree un módulo que contenga sus controladores de ruta HTTP de Actix Web y la lógica de representación HTML.

Desde la raíz de su proyecto, ejecute el siguiente comando:

touch src/pages.rs

Abre pages.rs y añade el siguiente código:

actix-quickstart/src/pages.rs
use actix_web::{get, web, HttpResponse, Responder};
use crate::{
AppState,
models::RestaurantRow,
services::restaurant_queries,
};
// Test endpoint to fetch all restaurants
#[get("/restaurants")]
async fn get_restaurants(data: web::Data<AppState>) -> impl Responder {
let result = restaurant_queries::fetch_all(&data.restaurants).await;
match result {
Ok(rows) => {
let html = render_table_page("All Restaurants", &rows);
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(html)
}
Err(e) => HttpResponse::InternalServerError().body(format!("DB error: {e}")),
}
}
// Endpoint to fetch restaurants by borough. Queens is used as an example.
#[get("/browse")]
async fn get_restaurants_by_borough(data: web::Data<AppState>) -> impl Responder {
let borough = "Queens"; // For demonstration, we use a fixed borough. This could be made dynamic.
let name = "Moon"; // For demonstration, we use a fixed name filter. This could be made dynamic.
let result = restaurant_queries::fetch_by_borough(&data.restaurants, borough, name).await;
match result {
Ok(rows) => {
let title = format!(r#"{} Restaurants with "{}" in the Name"#, borough, name);
let html = render_table_page(&title, &rows);
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(html)
}
Err(e) => HttpResponse::InternalServerError().body(format!("DB error: {e}")),
}
}
// HTML Renderer
fn render_table_page(title: &str, rows: &[RestaurantRow]) -> String {
let mut html = String::new();
html.push_str(r#"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
<title>"#);
html.push_str(title);
html.push_str(r#"</title>
</head>
<body class="w-full">
"#);
// Navigation Bar
html.push_str(r#"
<nav class="bg-white px-6 py-2 shadow-md w-full">
<div class="flex justify-between items-center">
<a href="/restaurants">
<img
alt="MongoDB Logo"
class="h-10 inline"
src="https://d3cy9zhslanhfa.cloudfront.net/media/3800C044-6298-4575-A05D5C6B7623EE37/4B45D0EC-3482-4759-82DA37D8EA07D229/webimage-8A27671A-8A53-45DC-89D7BF8537F15A0D.png"
/>
</a>
<a href="/browse" class="text-lime-800 text-lg font-semibold hover:text-lime-700">
Browse
</a>
</div>
</nav>
"#);
// Page Title
html.push_str(r#"<h2 class="text-lg font-semibold px-6 py-4">"#);
html.push_str(title);
html.push_str("</h2>");
// Table Wrapper
html.push_str(
r#"<div class="border border-gray-200 shadow-md rounded-lg overflow-hidden mx-6 mb-6">
<div class="relative w-full overflow-auto">
<table class="w-full caption-bottom text-sm">
<thead class="[&_tr]:border-b bg-gray-50">
<tr class="border-b transition-colors hover:bg-muted/50">
<th class="px-4 py-3 text-left text-sm font-bold text-gray-700 w-1/3">
Name
</th>
<th class="px-4 py-3 text-left text-sm font-bold text-gray-700 w-1/3">
Borough
</th>
<th class="px-4 py-3 text-left text-sm font-bold text-gray-700 w-1/3">
Cuisine
</th>
</tr>
</thead>
<tbody class="[&_tr:last_child]:border-0">
"#,
);
// Table Rows
for row in rows {
html.push_str(r#"<tr class="border-b transition-colors hover:bg-gray-50">"#);
html.push_str(r#"<td class="p-4 align-middle">"#);
html.push_str(row.name.as_deref().unwrap_or(""));
html.push_str("</td>");
html.push_str(r#"<td class="p-4 align-middle">"#);
html.push_str(row.borough.as_deref().unwrap_or(""));
html.push_str("</td>");
html.push_str(r#"<td class="p-4 align-middle">"#);
html.push_str(row.cuisine.as_deref().unwrap_or(""));
html.push_str("</td>");
html.push_str("</tr>");
}
// Closing tags
html.push_str(r#"
</tbody>
</table>
</div>
</div>
"#);
html.push_str("</body></html>");
html
}

Este módulo:

  • Define los puntos finales /restaurants y /browse.

  • Llama a los servicios de consulta de base de datos fetch_all y fetch_by_borough.

  • Representa una página HTML completa con Tailwind CSS y una barra de navegación reutilizable.

2

Reemplace el contenido de main.rs con el siguiente código:

actix-quickstart/src/main.rs
mod db;
mod models;
mod services;
mod pages;
use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use dotenv::dotenv;
use mongodb::bson::doc;
use mongodb::Collection;
use std::env;
use crate::models::RestaurantRow;
// Shared state to hold the MongoDB collection
#[derive(Clone)]
struct AppState {
restaurants: Collection<RestaurantRow>,
}
#[get("/health")]
async fn health_check() -> impl Responder {
HttpResponse::Ok().body("Healthy")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
let mongo_uri = env::var("MONGO_URI").expect("MONGO_URI must be set in .env file");
let port: u16 = env::var("PORT")
.unwrap_or_else(|_| "5050".to_string())
.parse()
.expect("PORT must be a valid u16 number");
print!("Starting server on port {port}...\n");
let db = db::init_db(&mongo_uri).await;
let restaurants: Collection<RestaurantRow> = db.collection::<RestaurantRow>("restaurants");
// Extra ping to be sure connection is working
let ping_result = db.run_command(doc! {"ping": 1},).await;
print!("MongoDB ping result: {ping_result:?}\n");
let state = AppState {restaurants};
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(state.clone()))
.service(health_check)
.service(pages::get_restaurants)
.service(pages::get_restaurants_by_borough)
})
.bind(("127.0.0.1", port))?
.run()
.await
}

Este archivo:

  • Declara los módulos utilizados en la aplicación (db, models, services, pages).

  • Define una estructura AppState que contiene la colección de restaurantes, compartida entre los controladores.

  • Implementa el punto final /health.

  • Lee MONGO_URI y PORT del entorno.

  • Inicializa la base de datos MongoDB y la colección restaurants.

  • Hace ping a su clúster MongoDB para verificar la conectividad.

  • Inicia un servidor HTTP web Actix y registra sus rutas:

    • /health

    • /restaurants

    • /browse

3

Antes de ejecutar la aplicación, asegúrese de que su árbol de archivos esté estructurado de manera similar a la siguiente:

actix-quickstart
├── Cargo.toml <-- Project config + dependencies>
├── .env <-- Environment variables>
└── src
├── main.rs <-- Application entry point>
├── db.rs <-- MongoDB connection module>
├── models.rs <-- RestaurantRow model + BSON mapping>
├── pages.rs <-- HTTP route handlers + HTML rendering>
└── services
├── mod.rs <-- Service module exports>
└── restaurant_queries.rs <-- MongoDB query services>

Las herramientas de Rust crean archivos adicionales, como target/, durante la compilación. Puedes ignorarlos sin problema.

Siga los pasos restantes para iniciar el servidor y ver los datos del restaurante procesados.

1

Desde la raíz de su proyecto, ejecute el siguiente comando para iniciar el servidor:

cargo run

Cargo compila su aplicación e inicia el servidor web Actix en el puerto 5050 definido en su archivo .env.

Cuando tenga éxito, verá un resultado similar al siguiente:

Starting server on port 5050...
MongoDB ping result: Ok(Document({"ok": Int32(1)}))
2

Abra su navegador web y navegue hasta http://localhost:5050/restaurants para ver todos los restaurantes.

Página de restaurantes
3

Haga clic en el Browse Enlace en el encabezado para ver una lista filtrada de restaurantes en Queens con Moon en el nombre.

Explorar la página de restaurantes

¡Felicitaciones por completar el tutorial de inicio rápido!

Después de completar estos pasos, tendrá una aplicación web Actix que se conecta a su implementación de MongoDB, ejecuta consultas en datos de restaurantes de muestra y presenta los resultados.

Para obtener más información sobre Actix Web, MongoDB y herramientas relacionadas, consulte:

Volver

Integración de cohetes

En esta página