Building Basic REST APIs with Rust: A Developer’s Guide
REST introduction::
REST as it stands for Representational State Transfer. It is used for designing networked applications and use Http requests to perform CRUD (Create, Read, Update, Delete) operations on resources. It is stateless, scalable and flexible architectural style.
If you want to know more about rest you can continue this section else you can jump to next section.
Background of REST
Functioning::
A) client-server client intiate the request and server sends data
b) statelessness :: no resource of client is stored
c) uniform interface:: restful apis have standard api to perform task eg. get to fetch data .
Other architectural patterns
— GRAPHQL :: allows clients to request only the data they need as it is more flexible. As a result, no over or under fetching
— RPC () :: Unlike Rpc focus on invoking function remotely , hiding underlying communication protocol. Also multiple types of data supported
— SOAP (simple object Access protocol) :: Relies upon XML as communication protocol whereas rest upon json or xml. soap support stateful operations through ws-security, ws-reliable messaging.
Section 2: Moving with RUST and REST practical
👉 Setting Up the Environment
- Installing Rust, Cargo [package manager for rust]
👉 Creating a basic rest server
For this guide I am using axum framework.
building a new rust project
cargo new project_new;
adding the required crates in cargo toml file for setting up basic rest api.
[package]
name = "project_new"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
axum = {version = "0.6.20", features = ["headers"]}
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.68"
tokio = { version = "1.0", features = ["full"] }
Once you have required crates you can go to main.rs file and add the following code to run the server. The code may vary from version if you use same version. this is ok.
#[tokio::main]
async fn main() {
let ip_address = "0.0.0.0:8000";
let app = Router::new()
.route("/", get(|| async { "Hello, Rust From AddyTech" }));
println!("server running on http://localhost:8000");
axum::Server::bind(&ip_address.parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
code info:
This Rust code uses the Axum web framework to create an HTTP server that listens on port 8000. It defines a single route for the root path (“/”) that responds with the message “Hello, Rust From AddyTech” when accessed via a GET request. The server starts and waits for incoming requests at the specified IP address and port.
- Post Request
// handler for creating a user
async fn create_user() -> impl IntoResponse{
Response::builder()
.status(StatusCode::CREATED)
.body(Body::from("user created successfully"))
.unwrap()
}
This Rust code is an asynchronous function
create_user()
that generates an HTTP response with a status of "Created" (HTTP 201) and a message "user created successfully" when called.
2. GET request
#[derive(Serialize)]
struct User {
name: String,
age: i32,
email: String,
}
async fn list_users() -> Json<Vec<User>> {
let users = vec![
User {
name: "Addy".to_string(),
age: 24,
email: "addytech@addytech.ai".to_string()
},
User {
name: "iop".to_string(),
age:24,
email:"dontlag@addytech.ai".to_string()
}
];
Json(users)
}
This Rust code is an asynchronous function
list_users()
that generates a JSON response containing information about two users: "Addy" and "iop" including their names, ages, and email addresses.
# now the main function becomes
#[tokio::main]
async fn main() {
let ip_address = "0.0.0.0:8000";
let app = Router::new()
.route("/create-user", post(create_user))
.route("/users", get(list_users));
println!("server running on http://localhost:8000");
axum::Server::bind(&ip_address.parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
I hope this help the learners. I am trying to improve myself so if any suggestion is more than welcome.
For full code you can check this github repository. I have bundled using docker-compose if you like to.