CRUD operations with Rust and Firebase (Realtime Database) 🦀+🔥

Carlos García Rosales
4 min readNov 16, 2022

--

¿Hablas español? Ver en español

I decided to do this article because I couldn’t find content in Spanish to integrate Firebase with Rust, but in the process I ran into a big challenge.

Firebase does not have an SDK Package for Rust

So there was only one option left to use the Realtime Database REST API provided by Firebase, luckily someone had already made a package that helps to communicate with said API.

So I got to work creating those functions.

Packages we will use:

I will add the Cargo file so that you know what dependencies the project uses.

[package]
name = "rust-firebase"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
firebase-rs = "2.0.5"
serde = "1.0.147"
serde_json = "1.0"
tokio = { version = "1.21.2", features = ["full"] }

Creating the structures we will use:

For this example we will use two simple structures a Response and a 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,
}

Now the main function:

We’ll make our main function Async to wait for API responses using the Tokio package.

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() {
}

Initializing a Firebase Client:

We will now create a firebase client with our database URL that we will use to pass it into functions.

Note 📝: If you want to use Auth replace the new function with auth and add your Auth token as the second parameter

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();
}

We will create two functions that will help us parse:

// 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()
}

We will create the corresponding methods:

Create 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 user by id:

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 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);
}

Delete user:

async fn delete_user(firebase_client: &Firebase, id: &String) {
let firebase = firebase_client.at("users").at(&id);
let _result = firebase.delete().await;
}

Using our functions and completing the main:

ara 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()
}

Conclusions:

Firebase and Rust are not good friends, there is still a lot to improve in this stack, from the lack of an official package to the fact that only being able to use Realtime Database makes using Firebase not a good idea since you don’t take advantage of all the benefits that Firebase gives you. Grants when fully used.

I wouldn’t use it in production until there was an official package.

See the repository

--

--

Carlos García Rosales

I am Software Developer working in @bayonet.io using the amazing programming language Go! I hope help you with my articles. follow me in my social medias!