main.rs
Decidí realizar este artículo debido a que no encontre contenido en español para integrar Firebase junto con Rust, pero en el proceso me encontre con un gran reto.
Entonces solo quedaba una opción usar el REST API de Realtime Database que proporcina Firebase, para mi suerte alguien ya había realizado un paquete que ayuda a comunicarse con dicho API.
Entonces me puse manos a la obra para crear esas funciones.
Agregaré el archivo de Cargo para que sepan que dependencias usa el proyecto.
~[package] name = "rust-firebase" version = "0.1.0" edition = "2021" [dependencies] firebase-rs = "2.0.5" serde = "1.0.147" serde_json = "1.0" tokio = { version = "1.21.2", features = ["full"] }
Para este ejemplo usaremos dos estructuras simple un Response y un User.
~use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] struct User { name: String, age: u32, email: String, } #[derive(Serialize, Deserialize, Debug)] struct Response { name: String, }
Haremos que nuestra main function sea Async para esperar las respuesta del API usando el paquete Tokio.
~use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] struct User { name: String, age: u32, email: String, } #[derive(Serialize, Deserialize, Debug)] struct Response { name: String, } #[tokio::main] async fn main() { }
Ahora crearemos un cliente de firebase con nuestra URL de la base de datos que usaremos para pasarlo en las funciones.
Nota 📝: Si deseas usar Auth remplaza la función new por auth y agrega tu Auth token como segundo parámetro
~use firebase_rs::*; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] struct User { name: String, age: u32, email: String, } #[derive(Serialize, Deserialize, Debug)] struct Response { name: String, } #[tokio::main] async fn main() { let firebase = Firebase::new("https://myproject.firebaseio.com").unwrap(); }
~// Convert a string to a Response fn string_to_reponse(s: &str) -> Response { serde_json::from_str(s).unwrap() } // Convert a string to a User fn string_to_user(s: &str) -> User { serde_json::from_str(s).unwrap() }
~async fn set_user(firebase_client: &Firebase, user: &User) -> Response { let firebase = firebase_client.at("users"); let _users = firebase.set::<User>(&user).await; return string_to_reponse(&_users.unwrap().data); }
~async fn get_users(firebase_client: &Firebase) -> HashMap<String,User> { let firebase = firebase_client.at("users"); let users = firebase.get::<HashMap<String, User>>().await; println!("{:?}", users); return users.unwrap(); }
~async fn get_user(firebase_client: &Firebase, id: &String) -> User { let firebase = firebase_client.at("users").at(&id); let user = firebase.get::<User>().await; return user.unwrap(); }
~async fn update_user(firebase_client: &Firebase, id: &String, user: &User) -> User { let firebase = firebase_client.at("users").at(&id); let _user = firebase.update::<User>(&user).await; return string_to_user(&_user.unwrap().data); }
~async fn delete_user(firebase_client: &Firebase, id: &String) { let firebase = firebase_client.at("users").at(&id); let _result = firebase.delete().await; }
Para este proceso crearemos un usuario luego obtendremos todos los usuarios en la base de datos despues obtendremos solo el usuario creado luego lo actualizaremos y al final lo eliminaremos.
~use std::collections::HashMap; use firebase_rs::*; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] struct User { name: String, age: u32, email: String, } #[derive(Serialize, Deserialize, Debug)] struct Response { name: String, } #[tokio::main] async fn main() { // Create the user let user = User { name: "Jhon Doe".to_string(), age: 25, email: "jhon.doe@mail.com".to_string(), }; // Create the Firebase Instance let firebase = Firebase::new("https://myproject.firebaseio.com").unwrap(); // Create the user let response = set_user(&firebase, &user).await; // Get all users let users = get_users(&firebase).await; println!("{:?}", users); // Get the user let mut user = get_user(&firebase, &response.name).await; println!("{:?}", user); // Update the user user.email = "updated.mail@gmail.com".to_string(); let updated_user = update_user(&firebase, &response.name, &user).await; println!("{:?}", updated_user); // Delete the user delete_user(&firebase, &response.name).await; println!("User deleted"); } // Create a user async fn set_user(firebase_client: &Firebase, user: &User) -> Response { let firebase = firebase_client.at("users"); let _users = firebase.set::<User>(&user).await; return string_to_reponse(&_users.unwrap().data); } // Get All users async fn get_users(firebase_client: &Firebase) -> HashMap<String,User> { let firebase = firebase_client.at("users"); let users = firebase.get::<HashMap<String, User>>().await; println!("{:?}", users); return users.unwrap(); } // Get a user async fn get_user(firebase_client: &Firebase, id: &String) -> User { let firebase = firebase_client.at("users").at(&id); let user = firebase.get::<User>().await; return user.unwrap(); } // Update a user async fn update_user(firebase_client: &Firebase, id: &String, user: &User) -> User { let firebase = firebase_client.at("users").at(&id); let _user = firebase.update::<User>(&user).await; return string_to_user(&_user.unwrap().data); } async fn delete_user(firebase_client: &Firebase, id: &String) { let firebase = firebase_client.at("users").at(&id); let _result = firebase.delete().await; } // Convert a string to a Response fn string_to_reponse(s: &str) -> Response { serde_json::from_str(s).unwrap() } // Convert a string to a User fn string_to_user(s: &str) -> User { serde_json::from_str(s).unwrap() }
Firebase y Rust no son buenos amigos aun hay mucho que mejorar en este stack desde la falta de un paquete oficial hasta el hecho de solo poder usar Realtime Database hace que usar Firebase no sea buena idea ya que no se aprovechan todos los beneficios que Firebase te otorga al usarlo de manera completa.
Yo no lo usaría en producción hasta que no hubiese un paquete oficial.
Repositorio del Proyecto