Part 7: REST API Development with Rust
Introduction
In this part of the Rust Web Development Tutorial series, we move into one of the most important real-world skills: building REST APIs with Rust.
REST APIs are the backbone of modern web and mobile applications. Whether you are building a SaaS platform, mobile backend, or microservices architecture, understanding how to design and implement APIs correctly is critical.
In this article, you will learn how to:
- Design RESTful APIs
- Create HTTP routes (GET, POST, PUT, DELETE)
- Handle JSON requests and responses
- Implement validation and proper error handling
- Structure API code for scalability
This part assumes you already understand Rust basics and async programming from previous parts.
What Is a REST API?
REST (Representational State Transfer) is an architectural style for building web services using HTTP.
A REST API typically:
- Uses HTTP methods (GET, POST, PUT, DELETE)
- Works with JSON data
- Is stateless
- Uses clear URL structures
Example resource-based URLs:
/users/users/{id}/products
Setting Up a Rust API Project
Create a new Rust project:
cargo new rust_rest_api
cd rust_rest_apiAdd dependencies to Cargo.toml:
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Creating a Basic API Server
Create a basic server in src/main.rs:
use axum::{routing::get, Router};
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(root));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
async fn root() -> &'static str {
"Rust REST API is running"
}Run the server:
cargo runOpen http://localhost:3000 in your browser.
Designing RESTful Endpoints
Good REST API design is about clarity and consistency.
Example Resource: Users
| Method | Endpoint | Description |
|---|---|---|
| GET | /users | Get all users |
| GET | /users/{id} | Get user by ID |
| POST | /users | Create new user |
| PUT | /users/{id} | Update user |
| DELETE | /users/{id} | Delete user |
Handling JSON Requests and Responses
Define a data model using Serde:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}Create a GET endpoint returning JSON:
use axum::{Json, routing::get, Router};
async fn get_users() -> Json<Vec<User>> {
let users = vec![
User { id: 1, name: "Alice".into(), email: "alice@test.com".into() },
User { id: 2, name: "Bob".into(), email: "bob@test.com".into() },
];
Json(users)
}
Creating POST Requests (Create Resource)
use axum::{Json, routing::post};
async fn create_user(Json(payload): Json<User>) -> Json<User> {
Json(payload)
}This automatically:
- Parses incoming JSON
- Validates structure
- Returns JSON response
Path Parameters and Dynamic Routes
use axum::extract::Path;
async fn get_user(Path(id): Path<u32>) -> String {
format!("Fetching user with ID: {}", id)
}Dynamic routes allow flexible API design.
Handling HTTP Status Codes
use axum::{http::StatusCode, response::IntoResponse};
async fn not_found() -> impl IntoResponse {
(StatusCode::NOT_FOUND, "Resource not found")
}Using proper status codes improves API reliability and client handling.
Error Handling Best Practices
Avoid exposing internal errors.
Recommended approach:
- Use custom error types
- Map errors to HTTP responses
- Log errors internally
Example:
enum ApiError {
NotFound,
BadRequest,
}
Structuring Your API Code
Recommended structure:
src/
├── main.rs
├── routes/
│ └── users.rs
├── models/
│ └── user.rs
├── handlers/
│ └── user_handler.rsThis keeps your API:
- Maintainable
- Scalable
- Easy to test
API Validation Basics
Validation ensures data integrity.
Common validations:
- Required fields
- Email format
- Length limits
Use separate validation logic instead of bloating handlers.
Testing REST APIs
Basic test example:
#[tokio::test]
async fn test_get_users() {
assert_eq!(2 + 2, 4);
}Comprehensive testing will be covered in a later part.
What You’ve Learned in Part 7
✅ REST API concepts
✅ Routing and handlers
✅ JSON serialization
✅ Request validation
✅ Error handling basics
You now have the skills to build production-grade REST APIs using Rust.
