Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Integrar MongoDB con Actix

Esta guía demuestra cómo compilar una aplicación web usando 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 seguros en cuanto a tipos.

La aplicación en 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 asíncrono/await ofrecen un manejo seguro de datos con garantías de verificación en tiempo de compilación.

  • Capa de presentación: Páginas HTML renderizadas en el servidor, estilizadas con Tailwind CSS, que muestran los datos del restaurante de muestra en una tabla.

Compilará una pequeña aplicación que:

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

  • Expone un endpoint /restaurants que lista todos los restaurantes

  • Expone un endpoint /browse que lista restaurantes en Queens con "Moon" en su nombre

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

El flexible modelo orientado a documentos de MongoDB almacena datos como documentos similares a BSON/JSON. Esto funciona perfectamente con structs Rust que modelan tus datos, sin capas ORM complejas ni migraciones de esquemas.

Cuando combinas Actix Web y el driver asíncrono MongoDB Rust, esta pila proporciona:

  • Estructuras de datos flexibles que pueden evolucionar sin migraciones costosas

  • E/S asíncrona y no bloqueante para altas concurrencias y APIs de alto rendimiento

  • 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 string, como en este tutorial)

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

  • La evolución de los esquemas a lo largo del tiempo

  • Alto rendimiento y concurrencia

  • Fuertes garantías en 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ía de Inicio rápido del controlador Rust.

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

1

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

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 completamente gestionado que aloja tus implementaciones de MongoDB. Si no tienes una implementación de MongoDB, crea un clúster de MongoDB de manera gratuita (no se requiere tarjeta de crédito) completando el tutorial Introducción a MongoDB. El tutorial de MongoDB Get Started también demuestra cómo cargar conjuntos de datos de muestra en tu clúster, incluida la base de datos sample_restaurants que utiliza este tutorial.

Importante

Asegúrese de tener el set de datos sample_restaurants cargado en el clúster antes de continuar. La ausencia del set de datos sample_restaurants da lugar a listas vacías de restaurantes en las páginas de muestra.

Para conectarte a tu clúster de MongoDB, utiliza un URI de conexión. Para aprender cómo recuperar tu URI de conexión, consulta la sección Agregar tu cadena de conexión del tutorial de inicio de 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:

actix-quickstart/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"

Instala las nuevas dependencias ejecutando el siguiente comando en tu 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: Entorno 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.

  • dotenvCarga variables de entorno desde un .env archivo para desarrollo local.

  • futures: Utilidades para trabajar con flujos asíncronos (utilizados para cursores de MongoDB).

Una vez que hayas configurado el Proyecto, sigue los pasos de esta sección para configurar las variables de entorno, establecer la conexión con MongoDB, definir el modelo de datos e implementar los servicios de consulta de la base de datos.

1

Crea un archivo .env en la raíz de tu proyecto para almacenar el URI de conexión de MongoDB.

Ejecuta el siguiente comando en el directorio raíz de tu proyecto:

touch .env

Abre .env y añade tu URI de conexión y el número de puerto:

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

Reemplace <your-mongodb-connection-uri> con el 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.

Ejecuta el siguiente comando en el directorio raíz de tu proyecto:

touch src/db.rs

Abre db.rs y añade el siguiente código para configurar el Cliente de MongoDB y la conexión a la base de datos:

actix-quickstart/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 desde tu 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

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

Ejecuta el siguiente comando en el directorio raíz de tu proyecto:

touch src/models.rs

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

actix-quickstart/src/models.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 de MongoDB. Utiliza anotaciones Serde para mapear campos de BSON a campos de estructuras Rust.

4

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

Ejecuta los siguientes comandos en la raíz de tu 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/services/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 los restaurantes filtrados por borough y por una regex insensible a mayúsculas y minúsculas en el nombre.

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

5

Ejecuta el siguiente comando en el directorio raíz de tu proyecto:

touch src/services/mod.rs

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

actix-quickstart/src/services/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 compartido de la aplicación

  • Exponer los puntos finales /restaurants y /browse

  • Renderizar páginas HTML con Tailwind CSS

1

Crea un módulo que contenga tus manejadores de rutas HTTP de Actix Web y la lógica de renderización HTML.

Desde la raíz de tu proyecto, ejecuta 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 consultas de base de datos fetch_all y fetch_by_borough.

  • Renderiza 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 desde el entorno.

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

  • Envía un ping a tu clúster de MongoDB para verificar la conectividad.

  • Inicia un servidor HTTP Actix Web y registra tus rutas:

    • /health

    • /restaurants

    • /browse

3

Antes de ejecutar la aplicación, asegúrate de que tu á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>

La herramienta de Rust crea archivos adicionales como target/ cuando se compila. Puedes ignorar estos archivos de forma segura.

Siga los pasos restantes para iniciar el servidor y visualizar los datos renderizados del restaurante.

1

Desde la raíz de tu proyecto, ejecuta el siguiente comando para iniciar el servidor:

cargo run

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

Cuando sea exitoso, verás una salida similar a la siguiente:

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

Abre tu navegador web y navega a 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

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

Después de completar estos pasos, tendrás una aplicación Actix Web que se conecta a tu implementación de MongoDB, ejecuta queries sobre datos de restaurantes de muestra y renderiza los resultados.

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

Volver

Integración con Rocket

En esta página