For many years, C and C++ have been the main low-level programming languages. C and C++ require manual deallocation of memory to prevent memory leaks which are the major cause of security breaches in Software. Rust comes in to offer memory safety and at the same time speed of execution that matches that of C.
In this blog, we will cover:
- About Rust Programming Language
- What is Ownership in Rust?
- About Rocket Framework and Diesel
About Rust Programming Language
Rust is a systems programming language that has been proven to be almost as fast as C. The big question would then be why have another language similar to C? Well, Rust is very different from C because it has inbuilt memory safety. When we talk about memory safety one would automatically think of a garbage collector, because that is what most high-level languages use, again sorry to disappoint, but Rust does not use a garbage collector it uses a new concept known as ownership which we will look at in a few.
The major difference between Rust and a low-level language like C is inbuilt memory safety. In a language like C and C++, you have to allocate and free memory on your own which has not proven to be effective. Microsoft admitted that the major cause of security issues is memory leakages and they decided to replace some of their legacy code with Rust. Rust also has a package manager. It was also discovered that Rust programs consume less electricity. Yes, less electricity due to its efficiency, which may save the company tons of money spent on Cloud Resources.
Did you know? In 2017, a team of 6 researchers from Portugal had run solutions for 10 programming problems in 27 different languages to monitor which language consumed the least electricity. The above image illustrates their findings.
What is Ownership in Rust?
As soon as a variable goes out of scope, it is dropped i.e its memory allocation is freed. Let us look at ownership in code but before that, important things to note are:
- Passing a variable as an argument to a function will either move(transfer ownership) it or copy it.
- Reassigning a value to a variable will either move(transfer ownership) it or copy it.
- Variables that are copied by default implement the Copy trait, most of which are primitive types and Immutable references i.e &T.
i32 is a primitive that implements Copy trait.
The figure code below shows the same (how ownership works in Rust):
About Rocket Framework and Diesel
Rocket is a Rust web framework that makes it easy to develop web applications. Since Rust is a compiled language the end result is an executable which is a plus. Diesel is an ORM built with Rust and it enables us to interact with relational databases by providing a layer of abstraction.
We are going to create a simple REST API that will allow us to add users to the Database and assign them roles. The repository is https://github.com/workfall/workfall-rocket-rs.
You should have the following installed on your computer:
- Rust lang – Comes with cargo which is a package manager for Rust. Rust packages are known as crates.
- PostgreSQL Database server
- Diesel CLI – This is installed directly on the system with the cargo install diesel_cli –no-default-features –features postgres command.
Initialization and Project Structure
We shall start by creating a new project using cargo, the command is cargo new hello-rocket –bin we are using –bin because we want the compiler to create an executable hence the main.rs file. The other option is –lib which is a library or in simple terms code which can be used by other crates hence the lib.rs file. In this project, we will use our diesel middleware as a library.
The Cargo.toml file contains information about all our dependencies. Allow us to look at it like a package.json file in Node.js.
The dotenvy crate allows us to use a .env file to manage our environment variables, serde crate allows us to serialize and deserialize JSON in our code and bcrypt to encrypt our passwords.
Note: Some files are auto generated so don’t sweat yourself creating them. i.e the migrations folder, diesel.toml, and schema file.
.env: The .env file will appear as shown below.
Next, we run diesel setup which will create the database for us if it does not exist and it will also create an empty migrations folder and a diesel.toml file. To run a migration use diesel migration generate <migration_name> I prefer the migration_name ordered with incremental numbers in order of relationships because errors might occur where we have joinable tables because the migrations are executed according to folder arrangement. In this case, we only have two tables, users and roles.
diesel migration generate 001-create-role
diesel migration generate 002-create-user
In this case, it makes sense to create a role first because every user will be required to have a role. This will generate 001-create-role and 002-create-user which will have up.sql and down.sql files each. The up.sql file contains the SQL queries describing the table columns while down.sql contains a SQL command to drop the table in the corresponding up.sql file.
up.sql: The up.sql file contains the SQL queries describing the table columns.
down.sql: contains a SQL command to drop the table in the corresponding up.sql file
To run the migrations use diesel migration run and to redo the migration i.e drop then recreate the table use diesel migration redo.
This file is generated automatically when the migrations run successfully.
Contains the entry point for our library and also imports other modules that are needed by our library.
We can access modules from our library lib.rs by using workfall_rocket_rs which is simply the package name as in Cargo.toml just with underscores used in place of spaces and/or hyphens.
In our folder structure, we are using each folder to represent a module. The Rust compiler knows that in every mod.rs file, we have a module(s). So we have routes, models, and services as modules.
Is the entry point of our Rocket application.
The main.rs file resolves all our routes and services and also contains some special Rocket catchers to catch some errors and give back the response. Disclaimer: Error handling was not well covered in this post.
These describe our data and also create a basis for serializing and deserializing JSON.
Contains structs that describe our Database models.
continuation of model.rs
The entry point for the models module.
Services module contains all the logic that is consumed by the routes module.
The entry point for the services module
A module that houses API paths/endpoints for the application.
The entry point for the routes module.
To run your application in development mode, use the cargo run command.
Adding a role:
Adding a user:
Getting a list of users:
Editing user info:
In this blog, we have demonstrated how to create a REST API with the Rust Rocket framework and Diesel ORM. Rust is a good language with quite a unique syntax. It is recommended that anyone who wants to learn the core syntax should look at the official documentation. In the next blog, we will come up with Rust, and dive into better error handling and also deployment in production – AWS for that matter. We will come up with more such use cases in our upcoming blogs.
If you are a Rust enthusiast and want to explore more about the above topics, here are a few of our blogs for your reference:
- AWS is in love with RUST and you should be too!
- How To Migrate RDS MySQL Database To RDS PostgreSQL Database Using AWS Database Migration Service(DMS)?
Keep Exploring -> Keep Learning -> Keep Mastering
At Workfall, we strive to provide the best tech and pay opportunities to kickass coders around the world. If you’re looking to work with global clients, build cutting-edge products and make big bucks doing so, give it a shot at workfall.com/partner/ today!