Introduction: Why Rust for REST API?
Rust is a modern systems programming language that combines the performance of C++ with memory safety guaranteed at compile time. In recent years, Rust has been actively used for building high-load web services and microservices. In this article, we will show you how to write a full-fledged REST API in Rust in 30 minutes using the Actix-web framework and the Serde library.
Why should you choose Rust for your API?
- Performance: Rust performs at the level of C/C++, which is critical for high-load systems.
- Safety: The ownership and borrowing system eliminates entire classes of memory-related errors.
- Asynchrony: Built-in async/await support allows efficient handling of thousands of connections.
- Ecosystem: Cargo (package manager) and crates.io make dependency management simple and convenient.
We will create a simple API for managing a Todo list that will support CRUD operations. You will learn how to configure routes, handle JSON, and work with application state.
Step 1: Project setup and dependency installation
First, let's create a new Rust project using Cargo. Open your terminal and run:
cargo new rust_todo_apicd rust_todo_apiNow let's edit the Cargo.toml file, adding the necessary dependencies:
[package]name = "rust_todo_api"version = "0.1.0"edition = "2021"
[dependencies]actix-web = "4"serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"tokio = { version = "1", features = ["full"] }uuid = { version = "1", features = ["v4"] }Let's break down why each library is needed:
- actix-web — a high-performance asynchronous web framework.
- serde — a library for serializing and deserializing data (JSON).
- serde_json — JSON format support for serde.
- tokio — an asynchronous runtime for Rust (actix-web uses it by default).
- uuid — generation of unique identifiers for our tasks.
After adding the dependencies, run cargo build to download and compile all packages. This may take a few minutes on the first run.
Step 2: Creating the data model and application structure
Let's create the src/main.rs file and define our task model. We will use a TodoItem structure with id, title, and completed fields:
use actix_web::{web, App, HttpServer, HttpResponse, middleware};use serde::{Deserialize, Serialize};use std::sync::Mutex;use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, Clone)]struct TodoItem { id: String, title: String, completed: bool,}
#[derive(Debug, Deserialize)]struct CreateTodoRequest { title: String,}
#[derive(Debug, Deserialize)]struct UpdateTodoRequest { title: Option<String>, completed: Option<bool>,}
struct AppState { todos: Mutex<Vec<TodoItem>>,}Pay attention to the important details:
SerializeandDeserialize— traits from serde that automatically generate code for working with JSON.Mutex— used for safe access to shared state from multiple threads.Uuid— generates unique identifiers for each task.
Now let's add the main function that will start the server and initialize the state:
#[actix_web::main]async fn main() -> std::io::R