MongoDB.local SF, Jan 15: See the speaker lineup & ship your AI vision faster. Use WEB50 to save 50%
Find out more >
Menu Docs
Página inicial do Docs
/ /

Integre o MongoDB com o Foguete

Neste guia, você pode aprender a criar um aplicação web Rust que utiliza oRocket como estrutura web. Foguete é uma estrutura para Rust que permite criar aplicativos da web seguros e com segurança de tipo.

O aplicação neste tutorial consiste nas seguintes camadas:

  • Camada de banco de dados: o MongoDB fornece armazenamento e recuperação de dados.

  • Camada de aplicativo: o Rock lida com solicitações HTTP, roteamento e processamento lógico.

  • Camada de apresentação: os modelos HTML renderizam dados de restaurantes em páginas da web.

Ao integrar o MongoDB com o Rust e o Foguete, você pode usar as características de segurança e desempenho da memória do Rust junto com o modelo de documento flexível do MongoDB. O sistema de tipos do Vector oferece garantias de tempo de compilação para os endpoints da API, e o armazenamento de documento do MongoDB funciona eficientemente com as bibliotecas de serialização do Rust, como o Serde.

A combinação de Rust, Foguete e MongoDB oferece suporte a aplicativos que exigem alto desempenho, segurança de tipo e escalabilidade. Como resultado, essa pilha é bem projetada para aplicativos do mundo real, como APIs de alta taxa de transferência, microsserviços ou sistemas que exigem garantias rigorosas de desempenho.

Este tutorial mostra como construir um aplicação da web que utiliza Rust e Foguete. O aplicação acessa dados de restaurantes de amostra, consulta os dados e os exibe por meio de modelos HTML com estilo. O tutorial também inclui instruções para se conectar a um cluster MongoDB hospedado no MongoDB Atlas e acessar e exibir dados de seu banco de dados.

Dica

Se você preferir se conectar ao MongoDB usando o driver Rust sem Foguete, consulte o tutorialInício Rápido do Driver Rust.

Siga as etapas nesta seção para instalar as dependências do projeto , criar um cluster do Atlas e configurar a estrutura do aplicação .

1

Para criar o aplicação Quick Start, instale o seguinte software em seu ambiente de desenvolvimento:

Pré-requisitos
Notas

Instale a versão estável mais recente usando rustup.

Editor de código

Este tutorial usa o Visual Studio Code com a extensão Rust, mas você pode usar o editor de sua escolha.

Aplicativo de terminal e shell

Para usuários do MacOS, use o Terminal ou um aplicativo semelhante. Para usuários do Windows, use o PowerShell.

2

O MongoDB Atlas é um serviço de banco de dados de nuvem totalmente gerenciado que hospeda suas implementações do MongoDB . Se você não tiver uma implementação do MongoDB , poderá criar um cluster do MongoDB gratuitamente (nenhum cartão de crédito necessário) concluindo o tutorial de Introdução ao MongoDB . O tutorial de Introdução ao MongoDB também demonstra como carregar conjuntos de dados de exemplo em seu cluster, incluindo o sample_restaurants banco de dados usado neste tutorial.

Para se conectar ao cluster MongoDB , você deve usar um URI de conexão. Para saber como recuperar seu URI de conexão, consulte a seção Adicionar sua string de conexão do tutorial de Introdução ao MongoDB .

Importante

Salve sua string de conexão em um local seguro.

3

Execute o seguinte comando no seu terminal para criar um novo projeto Rust :

cargo new rocket-quickstart
cd rocket-quickstart

Isso cria um novo projeto Rust chamado rocket-quickstart com a estrutura de diretórios padrão.

4

Navegue até o arquivo Cargo.toml e substitua seu conteúdo pelo seguinte código:

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

Instale as dependências executando o seguinte comando a partir do seu diretório rocket-quickstart:

cargo build

Este comando instala as seguintes dependências:

  • Foguete, a estrutura web do projeto com suporte a JSON

  • Serde, para serialização de dados

  • Driver MongoDB Rust, para operações MongoDB

  • Tokio, o tempo de execução assíncrono

  • shell_dyn_templates, para renderização de modelo de guiador

5

Para criar os diretórios e arquivos necessários para este aplicação, execute os seguintes comandos a partir do seu diretório 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

Esses comandos estruturam seu projeto para seguir o padrão de arquitetura modular do Rust, que agrupa arquivos em diferentes diretórios de acordo com sua finalidade. Após executar os comandos, você tem os seguintes diretórios:

  • src/models: contém estruturas de dados para modelar dados de restaurante

  • src/repository: Contém lógica de acesso ao banco de dados

  • src/api: contém manipuladores de endpoint HTTP

  • templates: contém um arquivo de modelo do Handlebars para renderização de dados

  • static: contém um arquivo CSS para estilo

Os comandos também criam arquivos de declaração de módulo para cada diretório src/, que listam os módulos disponíveis em seus diretórios correspondentes e permitem acessá-los em todo o aplicação.

Após configurar a estrutura e as dependências do projeto , siga as etapas desta seção para se conectar ao MongoDB e configurar seus modelos de dados.

1

Defina a variável de ambiente MONGO_URI para seu URI de conexão executando o seguinte comando no diretório rocket-quickstart:

export MONGO_URI="<connection URI>"

Substitua <connection URI> o espaço reservado pelo URI de conexão que você salvou em uma etapa anterior.

2

Navegue até o arquivo src/models/restaurant.rs e cole o seguinte código:

SDK-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 arquivo define os modelos Restaurant e Address, que representam os dados na collection de amostra do sample_restaurants.restaurants.

Para utilizar seus modelos em seus arquivos de projeto , você deve registrar o módulo restaurant, que corresponde ao arquivo restaurant.rs. Navegue até o arquivo src/models.rs e cole o seguinte código:

SDK-quickstart/src/models.rs
pub mod restaurant;
pub use restaurant::*;
3

Navegue até o arquivo src/repository/mongodb_repo.rs e cole o seguinte código:

SDK-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 arquivo acessa a coleção restaurants no banco de dados sample_restaurants . Em seguida, define os seguintes métodos de query que recuperam documentos da collection:

  • get_all_restaurants(): Recupera todos os documentos na coleção restaurants

  • get_filtered_restaurants(): recupera documentos na collection restaurants que têm um valor borough de "Queens" e um valor name contendo "Moon". O valor $options especifica que esta query name não diferencia maiúsculas de minúsculas.

Este código também inclui lógica para ignorar documentos que não podem ser desserializados. Isto evita erros quando os documentos não contêm cada campo definido no modelo Restaurant.

Em seguida, registre o módulo em src/repository.rs:

SDK-quickstart/src/repository.rs
pub mod mongodb_repo;
pub use mongodb_repo::*;

Depois de configurar a camada de dados, siga as etapas desta seção para criar manipuladores e modelos da API do Foguete para a interface do usuário.

1

Navegue até o arquivo src/api/restaurant_api.rs e cole o seguinte código:

SDK-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 cria os endpoints /restaurants e /restaurants/browse . Esses endpoints fornecem dados JSON de seus métodos de query que serão consumidos pelo código JavaScript do frontend para carregar e exibir dinamicamente as informações do restaurante.

Em seguida, registre o módulo API no src/api.rs:

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

Navegue até o arquivo src/main.rs e cole o seguinte código:

SDK-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 arquivo configura o servidor webRocket e configura as seguintes rotas:

  • /: Retorna o código HTML que formata a página do índice principal, que mostra todos os restaurantes

  • /browse: retorna o código HTML que formata a página de restaurantes filtrada

3

Navegue até o arquivo templates/index.hbs e cole o seguinte código:

SDK-quickstart/templates/index.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>

Este modelo do Handlebars usa JavaScript para criar uma interface web responsiva que carrega dinamicamente dados de restaurantes de seus endpoints API e exibe os restaurantes em um layout de grade interativo.

4

Adicione o seguinte código a static/style.css:

SDK
/* 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 arquivo CSS modela os dados do restaurante exibidos nas páginas da web.

Por fim, siga as etapas desta seção para executar seu aplicação da web e explorar os dados do restaurante usando a interface do navegador.

1

Navegue até o diretório do projeto e execute o seguinte comando:

cargo run

Se for bem-sucedida, a saída do comando será semelhante ao exemplo a seguir:

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

Abra http://:127.0.0.1 8000 em seu navegador da web. A página de destino inicial exibe todos os restaurantes na sample_restaurants.restaurants coleção:

A página de destino que exibe todos os restaurantes

Em seguida, clique no botão Browse Filtered para visualizar os restaurantes no Queins que têm "Moon" em seu nome:

A página web que exibe os restaurantes filtrados
3

Você também pode testar diretamente os endpoints da API subjacentes executando os seguintes comandos no seu terminal:

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

Esses endpoints retornam os mesmos dados exibidos na interface da web, formatados como documentos JSON.

Parabéns por concluir o tutorial Início rápido! Depois de concluir essas etapas, você tem um aplicação web Rust and Rock que se conecta à implementação do MongoDB , executa queries em dados de restaurantes de exemplo e exibe os resultados em uma interface web hospedada localmente.

Para saber mais sobre Rust, Foguete e MongoDB, consulte os seguintes recursos:

Voltar

Veja a fonte

Nesta página