In today’s world of web development, efficiency and performance are paramount. The introduction of Rust, a language designed for performance and safety, offers an exciting possibility for backend developers. In this tutorial, we will explore how to create a CRUD (Create, Read, Update, Delete) web application using the Rust language.
Setting Up Your Rust Environment
First, you need to set up your Rust environment. If you don’t have Rust installed yet, head over to Rust-lang.org and follow the instructions there.
Creating a New Project
Once Rust is installed, you can create a new project by typing the following command in your terminal:
cargo new rust_crud_app
cd rust_crud_app
Including Dependencies
For our CRUD application, we will be using two main dependencies: Rocket
for our web framework and Diesel
for interacting with our database. To include them in your project, add the following lines to your Cargo.toml
file:
[dependencies]
rocket = "0.4"
diesel = { version = "1.4.0", features = ["postgres"] }
Run cargo build
to download and compile these dependencies.
Establishing a Database Connection
Next, we will set up a PostgreSQL database connection using Diesel. Diesel offers a neat command-line tool that can help us with this. First, install it by running:
cargo install diesel_cli
Creating CRUD Operations with Rust
Creating Records
With the database connection established, it’s time to implement our CRUD operations. First, we’ll tackle “Create.” To create a new record, we can use Diesel’s insert_into
function.
Import the necessary modules and define the required structs and schema.
use diesel::prelude::*;
use diesel::insert_into;
use diesel::result::Error;
// Import the schema and the table struct
use crate::schema::your_table;
use crate::schema::your_table::dsl::*;
// Define the struct representing your table's columns
#[derive(Insertable)]
#[table_name = "your_table"]
struct YourTable {
// Define the fields of your table's columns
field1: String,
field2: i32,
// ...
}
Implement a function to create a new record by inserting into the database.
fn create_record(conn: &PgConnection, field1: String, field2: i32) -> Result<usize, Error> {
let new_record = YourTable {
field1,
field2,
// ...
};
let inserted_rows = insert_into(your_table)
.values(&new_record)
.execute(conn)?;
Ok(inserted_rows)
}
In the create_record
function above, we create a new instance of YourTable
with the provided field values. Then, using the insert_into
function, we specify the table we want to insert into (your_table
), provide the values (&new_record
), and execute the query by calling execute(conn)
on it. Finally, we return the number of inserted rows as a Result<usize, Error>
.
Make sure to replace your_table
with the actual name of your table in the schema, and adjust the field names and types in YourTable
according to your table’s structure.
Remember to handle potential errors returned by Diesel’s functions, such as the connection error or any database-specific issues.
With this implementation, you should be able to create new records using Diesel’s insert_into
function in your Rust application.
Reading Records
Next, we will implement the “Read” operation. For this, we’ll use Diesel’s load
function.
To implement the “Read” operation using Diesel’s load
function, you can follow these steps:
Import the necessary modules and define the required structs and schema.
use diesel::prelude::*;
use diesel::result::Error;
// Import the schema and the table struct
use crate::schema::your_table;
use crate::schema::your_table::dsl::*;
// Define the struct representing your table's columns
#[derive(Queryable)]
struct YourTable {
// Define the fields of your table's columns
field1: String,
field2: i32,
// ...
}
Implement a function to read a record from the database.
fn read_record(conn: &PgConnection, target_field_value: i32) -> Result<Option<YourTable>, Error> {
let record = your_table
.filter(field2.eq(target_field_value))
.first(conn)
.optional()?;
Ok(record)
}
In the read_record
function above, we use the your_table
and field2
from the schema to filter records based on the specified condition (field2.eq(target_field_value)
). We then call first(conn)
to retrieve the first record matching the condition, and optional()
to handle the case where no record is found. The result is returned as an Option<YourTable>
.
Make sure to replace your_table
with the actual name of your table in the schema, and adjust the field names and types in YourTable
according to your table’s structure. Additionally, modify the target_field_value
parameter and the filter condition to match your specific search criteria.
Remember to handle potential errors returned by Diesel’s functions, such as the connection error or any database-specific issues.
With this implementation, you should be able to read records from the database using Diesel’s load
function in your Rust application.
Updating Records
The “Update” operation comes next. For updating a record, Diesel’s filter
and set
functions can be very handy.
To implement the “Update” operation using Diesel’s filter
and set
functions, you can follow these steps:
Import the necessary modules and define the required structs and schema.
use diesel::prelude::*;
use diesel::result::Error;
// Import the schema and the table struct
use crate::schema::your_table;
use crate::schema::your_table::dsl::*;
// Define the struct representing your table's columns
#[derive(Queryable, AsChangeset)]
#[table_name = "your_table"]
struct YourTable {
// Define the fields of your table's columns
field1: Option<String>,
field2: Option<i32>,
// ...
}
Implement a function to update a record in the database.
fn update_record(
conn: &PgConnection,
target_field_value: i32,
new_field1_value: Option<String>,
new_field2_value: Option<i32>,
) -> Result<usize, Error> {
let updated_rows = diesel::update(your_table.filter(field2.eq(target_field_value)))
.set((
field1.eq(new_field1_value),
field2.eq(new_field2_value),
// ...
))
.execute(conn)?;
Ok(updated_rows)
}
In the update_record
function above, we use the your_table
, field2
, field1
, and field2
from the schema to filter records based on the specified condition (field2.eq(target_field_value)
). We then use the set
function to specify the new values for the fields to be updated (field1.eq(new_field1_value)
and field2.eq(new_field2_value)
). You can adjust the set
function call to include all the fields you want to update. Finally, we execute the query by calling execute(conn)
on it and return the number of updated rows as a Result<usize, Error>
.
Make sure to replace your_table
with the actual name of your table in the schema, and adjust the field names and types in YourTable
according to your table’s structure. Additionally, modify the target_field_value
, new_field1_value
, new_field2_value
, and the set
function calls to match your specific update criteria.
Remember to handle potential errors returned by Diesel’s functions, such as the connection error or any database-specific issues.
With this implementation, you should be able to update records in the database using Diesel’s filter
and set
functions in your Rust application.
Deleting Records
Finally, we will implement the “Delete” operation. This can be achieved with Diesel’s filter
and delete
functions.
To implement the “Delete” operation using Diesel’s filter
and delete
functions, you can follow these steps:
Import the necessary modules and define the required structs and schema.
use diesel::prelude::*;
use diesel::result::Error;
// Import the schema and the table struct
use crate::schema::your_table;
use crate::schema::your_table::dsl::*;
Implement a function to delete a record from the database.
fn delete_record(conn: &PgConnection, target_field_value: i32) -> Result<usize, Error> {
let deleted_rows = diesel::delete(your_table.filter(field2.eq(target_field_value)))
.execute(conn)?;
Ok(deleted_rows)
}
In the delete_record
function above, we use the your_table
and field2
from the schema to filter records based on the specified condition (field2.eq(target_field_value)
). We then call execute(conn)
on the delete
function to execute the delete query. The number of deleted rows is returned as a Result<usize, Error>
.
Make sure to replace your_table
with the actual name of your table in the schema, and adjust the field names and types in the filter
function call to match your specific delete criteria.
Remember to handle potential errors returned by Diesel’s functions, such as the connection error or any database-specific issues.
With this implementation, you should be able to delete records from the database using Diesel’s filter
and delete
functions in your Rust application.
Conclusion on Rust CRUD Tutorial
Congratulations, you’ve built your first CRUD application in Rust! Rust’s promise of performance and safety combined with Diesel’s database management capabilities make it a powerful tool for backend development.
Related Articles