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
/ /

Integra MongoDB con Rocket

En esta guía, aprenderá a crear una aplicación web en Rust que utiliza Rocket como framework. Rocket es un framework para Rust que permite crear aplicaciones web seguras y con seguridad de tipos.

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

  • Capa de base de datos: MongoDB proporciona almacenamiento y recuperación de datos.

  • Capa de aplicación: Rocket gestiona las solicitudes HTTP, la gestión de rutas y el procesamiento lógico.

  • Capa de presentación: las plantillas HTML representan datos del restaurante en páginas web.

Al integrar MongoDB con Rust y Rocket, puedes aprovechar la seguridad de memoria y las características de rendimiento de Rust junto con el modelo orientado a documentos de MongoDB. El sistema de tipos de Rocket garantiza garantías en tiempo de compilación para tus endpoints de API, y el almacenamiento de documentos de MongoDB funciona de manera eficiente con las librerías de serialización de Rust, como Serde.

La combinación de Rust, Rocket y MongoDB da soporte a aplicaciones que requieren alto rendimiento, seguridad de tipos y escalabilidad. Como resultado, esta pila está bien diseñada para aplicaciones del mundo real, tales como API de alto rendimiento, microservicios o sistemas que requieren estrictas garantías de rendimiento.

Este tutorial te muestra cómo compilar una aplicación web que utilice Rust y Rocket. La aplicación accede a datos de restaurantes de muestra, query los datos y los muestra a través de plantillas HTML con estilos. El tutorial también incluye instrucciones para conectarse a un clúster de MongoDB alojado en MongoDB Atlas, acceder y mostrar datos de su base de datos.

Tip

Si prefiere conectarse a MongoDB utilizando el controlador Rust sin Rocket, consulte la Tutorial Guía rápida del controlador Rust.

Sigue los pasos de esta sección para instalar las dependencias del proyecto, crear un clúster de Atlas y configurar la estructura de la aplicación.

1

Para crear la aplicación Quick Start, instala el siguiente software en tu entorno de desarrollo:

Requisito previo
notas

Instala la última versión estable usando rustup.

Editor de código

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

Aplicación de terminal y shell

Para usuarios de macOS, usen Terminal o una aplicación similar. Para usuarios de Windows, usen PowerShell.

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, puedes crear un clúster de MongoDB de forma gratuita (no se requiere tarjeta de crédito) completando el tutorial Introducción a MongoDB. El tutorial para comenzar con MongoDB también muestra cómo cargar conjuntos de datos de muestra en tu clúster, incluyendo la base de datos sample_restaurants que se usa en este tutorial.

Para conectarte a tu clúster de MongoDB, debes usar un URI de conexión. Para saber cómo recuperar tu URI de conexión, consulta la sección Agrega tu cadena de conexión del tutorial Primeros pasos de MongoDB.

Importante

Guarda tu cadena de conexión en una ubicación segura.

3

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

cargo new rocket-quickstart
cd rocket-quickstart

Esto crea un nuevo proyecto Rust llamado rocket-quickstart con la estructura de directorio predeterminada.

4

Navega al archivo Cargo.toml y reemplaza su contenido con el siguiente código:

inicio rápido de cohetes/Cargo.toml
[package]
name = "rocket-quickstart"
version = "0.1.0"
edition = "2024"
[dependencies]
rocket = {version = "0.5.0", features = ["json"]}
serde = "1.0.136"
dotenv = "0.15.0"
tokio = {version = "1.32.0", features = ["full"]}
rocket_dyn_templates = { version = "0.1.0", features = ["handlebars"] }
[dependencies.mongodb]
version = "3.4.1"

Instala las dependencias ejecutando el siguiente comando desde tu directorio rocket-quickstart:

cargo build

Este comando instala las siguientes dependencias:

  • Rocket, el marco web del proyecto con soporte para JSON

  • Serde, para la serialización de datos

  • Controlador Rust de MongoDB para operaciones de MongoDB

  • Tokio, el entorno de ejecución asíncrono

  • rocket_dyn_templates, para la representación de plantillas Handlebars

5

Para crear los directorios y archivos necesarios para esta aplicación, ejecute los siguientes comandos desde su directorio rocket-quickstart:

mkdir -p src/models src/repository src/api templates static
touch src/models/restaurant.rs src/repository/mongodb_repo.rs src/api/restaurant_api.rs
touch src/models.rs src/repository.rs src/api.rs
touch templates/index.hbs static/style.css

Estos comandos estructuran tu proyecto para seguir el patrón de arquitectura modular de Rust, que agrupa los archivos en diferentes directorios según su propósito. Después de ejecutar los comandos, tienes los siguientes directorios:

  • src/models: Contiene estructuras de datos para modelar los datos de los restaurantes

  • src/repository: Contiene lógica de acceso a la base de datos

  • src/api: Contiene manejadores de endpoints HTTP

  • templates:Contiene un archivo de plantilla Handlebars para representar datos

  • static:Contiene un archivo CSS para aplicar estilo.

Los comandos también crean archivos de declaración de módulo para cada directorio src/, que listan los módulos disponibles en sus directorios correspondientes y permiten acceder a ellos en toda la aplicación.

Después de configurar la estructura y las dependencias del proyecto, siga los pasos de esta sección para conectarse a MongoDB y configurar sus modelos de datos.

1

Establezca la variable de entorno MONGO_URI en su URI de conexión ejecutando el siguiente comando desde el directorio rocket-quickstart:

export MONGO_URI="<connection URI>"

Reemplace <connection URI> el marcador de posición con la URI de conexión que guardó en un paso anterior.

2

Navega al archivo src/models/restaurant.rs y pega el siguiente código:

rocket-quickstart/src/models/restaurant.rs
use serde::{Deserialize, Serialize};
use mongodb::bson::oid::ObjectId;
#[derive(Debug, Serialize, Deserialize)]
pub struct Restaurant {
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
pub id: Option<ObjectId>,
pub name: Option<String>,
pub borough: Option<String>,
pub cuisine: Option<String>,
pub address: Option<Address>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Address {
pub building: Option<String>,
pub street: Option<String>,
pub zipcode: Option<String>,
}

Este archivo define los modelos Restaurant y Address, que representan los datos en la colección de muestra sample_restaurants.restaurants.

Para utilizar tus modelos en los archivos del proyecto, debes registrar el módulo restaurant, que corresponde al archivo restaurant.rs. Navegar al archivo src/models.rs y pegar el siguiente código:

inicio rápido de cohetes/src/models.rs
pub mod restaurant;
pub use restaurant::*;
3

Navega al archivo src/repository/mongodb_repo.rs y pega el siguiente código:

rocket-quickstart/src/repository/mongodb_repo.rs
use std::env;
use mongodb::{
bson::{extjson::de::Error, doc},
Client, Collection
};
use crate::models::Restaurant;
pub struct MongoRepo {
col: Collection<Restaurant>,
}
impl MongoRepo {
pub async fn init() -> Self {
dotenv::dotenv().ok();
let uri = match env::var("MONGO_URI") {
Ok(v) => v.to_string(),
Err(_) => format!("Error loading env variable"),
};
let client = Client::with_uri_str(uri).await.unwrap();
let db = client.database("sample_restaurants");
let col: Collection<Restaurant> = db.collection("restaurants");
MongoRepo { col }
}
pub async fn get_all_restaurants(&self) -> Result<Vec<Restaurant>, Error> {
let mut cursor = self
.col
.find(doc! {})
.await
.map_err(|e| Error::DeserializationError { message: e.to_string() })?;
let mut restaurants: Vec<Restaurant> = Vec::new();
while cursor.advance().await.map_err(|e| Error::DeserializationError { message: e.to_string() })? {
match cursor.deserialize_current() {
Ok(restaurant) => restaurants.push(restaurant),
Err(e) => {
// Skips documents that can't be deserialized and logs the error
eprintln!("Warning: Skipping document due to deserialization error: {}", e);
continue;
}
}
}
Ok(restaurants)
}
pub async fn get_filtered_restaurants(&self) -> Result<Vec<Restaurant>, Error> {
let filter = doc! {
"borough": "Queens",
"name": { "$regex": "Moon", "$options": "i" }
};
let mut cursor = self
.col
.find(filter)
.await
.map_err(|e| Error::DeserializationError { message: e.to_string() })?;
let mut restaurants: Vec<Restaurant> = Vec::new();
while cursor.advance().await.map_err(|e| Error::DeserializationError { message: e.to_string() })? {
match cursor.deserialize_current() {
Ok(restaurant) => restaurants.push(restaurant),
Err(e) => {
// Skips documents that can't be deserialized and logs the error
eprintln!("Warning: Skipping document due to deserialization error: {}", e);
continue;
}
}
}
Ok(restaurants)
}
}

Este archivo accede a la colección restaurants en la base de datos sample_restaurants. Luego, define los siguientes métodos de query que recuperan documentos de la colección:

  • get_all_restaurants(): Recupera todos los documentos en la colección restaurants

  • get_filtered_restaurants(): Recupera documentos en la colección restaurants que tienen un valor borough de "Queens" y un valor name que contiene "Moon". El valor $options especifica que esta name query no distingue entre mayúsculas y minúsculas.

Este código también incluye lógica para omitir documentos que no pueden ser deserializados. Esto evita errores cuando los documentos no contienen cada campo definido en el Restaurant modelo.

Luego, registre el módulo en src/repository.rs:

rocket-quickstart/src/repositorio.rs
pub mod mongodb_repo;
pub use mongodb_repo::*;

Después de configurar la capa de datos, siga los pasos de esta sección para crear controladores y plantillas de Rocket API para la interfaz de usuario.

1

Navega al archivo src/api/restaurant_api.rs y pega el siguiente código:

rocket-quickstart/src/api/restaurant_api.rs
use rocket::{State, serde::json::Json, get, http::Status};
use crate::{models::Restaurant, repository::MongoRepo};
#[get("/restaurants")]
pub async fn get_all_restaurants(db: &State<MongoRepo>) -> Result<Json<Vec<Restaurant>>, Status> {
let restaurants = db.get_all_restaurants().await;
match restaurants {
Ok(restaurants) => Ok(Json(restaurants)),
Err(_) => Err(Status::InternalServerError),
}
}
#[get("/restaurants/browse")]
pub async fn get_filtered_restaurants(db: &State<MongoRepo>) -> Result<Json<Vec<Restaurant>>, Status> {
let restaurants = db.get_filtered_restaurants().await;
match restaurants {
Ok(restaurants) => Ok(Json(restaurants)),
Err(_) => Err(Status::InternalServerError),
}
}

Este código crea los endpoints /restaurants y /restaurants/browse. Estos endpoints proporcionan datos JSON de tus métodos query que serán consumidos por el código JavaScript frontend para cargar y mostrar dinámicamente la información de los restaurantes.

Luego, registra el módulo de la API en src/api.rs:

rocket-quickstart/src/api.rs
pub mod restaurant_api;
pub use restaurant_api::*;
2

Navega al archivo src/main.rs y pega el siguiente código:

rocket-quickstart/src/main.rs
mod api;
mod models;
mod repository;
#[macro_use]
extern crate rocket;
use rocket::{get, fs::FileServer, response::content::RawHtml};
use rocket_dyn_templates::Template;
use api::restaurant_api::{get_all_restaurants, get_filtered_restaurants};
use repository::MongoRepo;
#[get("/")]
async fn index() -> RawHtml<String> {
let template_content = std::fs::read_to_string("templates/index.hbs").unwrap_or_else(|_| {
r#"<!DOCTYPE html>
<html><head><title>Error</title></head>
<body><h1>Template not found</h1></body></html>"#.to_string()
});
RawHtml(template_content)
}
#[get("/browse")]
async fn browse() -> RawHtml<String> {
let template_content = std::fs::read_to_string("templates/index.hbs").unwrap_or_else(|_| {
r#"<!DOCTYPE html>
<html><head><title>Error</title></head>
<body><h1>Template not found</h1></body></html>"#.to_string()
});
RawHtml(template_content)
}
#[rocket::launch]
async fn rocket() -> _ {
let db = MongoRepo::init().await;
rocket::build()
.manage(db)
.mount("/", routes![index, browse, get_all_restaurants, get_filtered_restaurants])
.mount("/static", FileServer::from("static/"))
.attach(Template::fairing())
}

Este archivo configura el servidor web Rocket y configura las siguientes rutas:

  • /: Devuelve el código HTML que formatea la página principal del índice, que muestra todos los restaurantes

  • /browse: Devuelve código HTML que da formato a la página de restaurantes filtrados

3

Navega al archivo templates/index.hbs y pega el siguiente código:

rocket-quickstart/templates/índice.hbs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Explorer</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="container">
<header>
<h1>Restaurant Directory</h1>
</header>
<div class="controls">
<a href="/" class="btn" id="all-btn">All Restaurants</a>
<a href="/browse" class="btn" id="browse-btn">Browse Filtered</a>
</div>
<div id="restaurants-container">
<div class="loading">Loading restaurants...</div>
</div>
</div>
<script>
// Sets the active button based on the current path
const path = window.location.pathname;
if (path === '/browse') {
document.getElementById('browse-btn').classList.add('active');
} else {
document.getElementById('all-btn').classList.add('active');
}
// Loads the restaurant documents
async function loadRestaurants() {
try {
const apiEndpoint = path === '/browse' ? '/restaurants/browse' : '/restaurants';
const response = await fetch(apiEndpoint);
const restaurants = await response.json();
displayRestaurants(restaurants);
} catch (error) {
document.getElementById('restaurants-container').innerHTML =
'<div class="error">Error loading restaurants. Please try again later.</div>';
}
}
// Displays restaurants in a grid format
function displayRestaurants(restaurants) {
const container = document.getElementById('restaurants-container');
if (restaurants.length === 0) {
container.innerHTML = '<div class="error">No restaurants found.</div>';
return;
}
const restaurantsHTML = restaurants.map(function(restaurant) {
return '<div class="restaurant-card">' +
'<div class="restaurant-name">' + (restaurant.name || 'Unknown Name') + '</div>' +
(restaurant.cuisine ? '<div class="cuisine-tag">' + restaurant.cuisine + '</div>' : '') +
(restaurant.borough ? '<div class="restaurant-info"><strong>Borough:</strong> ' + restaurant.borough + '</div>' : '') +
(restaurant.restaurant_id ? '<div class="restaurant-info"><strong>ID:</strong> ' + restaurant.restaurant_id + '</div>' : '') +
(restaurant.address ?
'<div class="address">' +
(restaurant.address.building ? restaurant.address.building + ' ' : '') +
(restaurant.address.street ? restaurant.address.street : '') +
(restaurant.address.zipcode ? ', ' + restaurant.address.zipcode : '') +
'</div>' : '') +
'</div>';
}).join('');
container.innerHTML = '<div class="restaurants-grid">' + restaurantsHTML + '</div>';
}
loadRestaurants();
</script>
</body>
</html>

Esta Handlebars plantilla utiliza JavaScript para crear una interfaz web responsiva que carga dinámicamente datos de restaurantes desde tus endpoints API y muestra los restaurantes en un diseño de cuadrícula interactivo.

4

Agrega el siguiente código a static/style.css:

inicio rápido de cohetes/estático/estilo.css
/* Modern, clean styling for the restaurant app */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.6;
color: #333;
background: rgb(198, 240, 209);
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 40px;
color: rgb(0, 0, 0);
}
h1 {
font-size: 3rem;
margin-bottom: 10px;
}
.subtitle {
font-size: 1.2rem;
opacity: 0.9;
}
.controls {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 30px;
}
.btn {
background: white;
color: #0d8958;
border: none;
padding: 12px 24px;
border-radius: 25px;
font-weight: 600;
text-decoration: none;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
}
.btn.active {
background: #0d8958;
color: white;
}
.restaurants-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
margin-top: 20px;
}
.restaurant-card {
background: white;
border-radius: 15px;
padding: 20px;
box-shadow: 0 8px 25px rgba(0,0,0,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.restaurant-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 35px rgba(0,0,0,0.15);
}
.restaurant-name {
font-size: 1.4rem;
font-weight: 700;
color: #000000;
margin-bottom: 10px;
}
.restaurant-info {
margin-bottom: 8px;
}
.restaurant-info strong {
color: #555;
}
.cuisine-tag {
display: inline-block;
background: #0d8958;
color: white;
padding: 4px 12px;
border-radius: 15px;
font-size: 0.85rem;
font-weight: 600;
margin-top: 10px;
}
.address {
color: #666;
font-style: italic;
margin-top: 8px;
}
.loading {
text-align: center;
color: white;
font-size: 1.2rem;
margin: 40px 0;
}
.error {
text-align: center;
color: #ff6b6b;
background: white;
padding: 20px;
border-radius: 10px;
margin: 20px 0;
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
h1 {
font-size: 2rem;
}
.controls {
flex-direction: column;
align-items: center;
}
.restaurants-grid {
grid-template-columns: 1fr;
}
}

Este archivo CSS da estilo a los datos del restaurante mostrados en las páginas web.

Por último, sigue los pasos de esta sección para ejecutar tú aplicación web y explorar los datos del restaurante mediante la interfaz del navegador.

1

Navegue al directorio de su proyecto y ejecute el siguiente comando:

cargo run

Si la operación es exitosa, la salida del comando se asemeja al siguiente ejemplo:

Configured for debug.
>> address: 127.0.0.1
>> port: 8000
...
Routes:
>> (index) GET /
>> (browse) GET /browse
>> (get_all_restaurants) GET /restaurants
>> (get_filtered_restaurants) GET /restaurants/browse
>> (FileServer: static/) GET /static/<path..> [10]
Fairings:
>> Templating (ignite, liftoff, request)
>> Shield (liftoff, response, singleton)
Shield:
>> X-Frame-Options: SAMEORIGIN
>> Permissions-Policy: interest-cohort=()
>> X-Content-Type-Options: nosniff
Templating:
>> directory: templates
>> engines: ["hbs"]
Rocket has launched from http://127.0.0.1:8000
2

Abre http://127.0.0.1:8000 en tu navegador web. La página de inicio muestra todos los restaurantes en la colección sample_restaurants.restaurants:

La página de inicio que muestra todos los restaurantes

Luego, haga clic en el Browse Filtered botón para ver restaurantes en Queens que tengan "Moon" en su nombre:

La página web que muestra los restaurantes filtrados
3

También puedes probar los puntos finales de la API subyacente directamente ejecutando los siguientes comandos desde tu terminal:

curl http://127.0.0.1:8000/restaurants
curl http://127.0.0.1:8000/restaurants/browse

Estos endpoints devuelven los mismos datos que se muestran en la interfaz web, formateados como documentos JSON.

¡Felicitaciones por completar el tutorial de Inicio rápido! Después de completar estos pasos, tienes una aplicación web de Rust y Rocket que se conecta a tu implementación de MongoDB, ejecuta consultas en datos de muestra de restaurantes y muestra los resultados en una interfaz web alojada localmente.

Para obtener más información sobre Rust, Rocket y MongoDB, consulte los siguientes recursos:

Volver

Ve el origen

En esta página