Skip to content

JonniTech/Rust-Notes-API

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust Notes API

A production-style REST API for managing personal notes. Built with Rust, Axum, and PostgreSQL. Features JWT-based authentication, pagination, OpenAPI documentation with Swagger UI, and Docker support.


Aim

Build a secure, performant, and well-documented REST API that demonstrates production-grade Rust backend development practices. The project serves as both a functional notes management service and a reference implementation for modern Rust web development.

Problem

Many Rust backend tutorials and starter projects lack real-world production features such as:

  • Structured error handling with proper HTTP status codes
  • JWT-based authentication with password hashing
  • Request validation and sanitization
  • Pagination for list endpoints
  • Auto-generated OpenAPI documentation
  • Containerized development and deployment
  • Clean separation of concerns (controllers, services, repositories)

This gap makes it difficult for developers to learn production patterns in Rust or quickly bootstrap a new API project.

Solution

The Rust Notes API provides a complete, well-architected backend with all the essential production features out of the box:

  • Clean monolith architecture with clear separation of concerns (routes, controllers, services, middleware, DTOs)
  • JWT authentication with Argon2 password hashing for secure credential storage
  • CRUD operations for personal notes scoped to authenticated users
  • Pagination support with configurable page size
  • Global error handling that produces consistent JSON error responses
  • Auto-generated OpenAPI 3.1 documentation with Swagger UI
  • Structured logging with configurable verbosity
  • Docker Compose setup for one-command local development
  • Multi-stage Docker build for production deployment

Features

  • User registration and login with email and password
  • JWT-based authentication (HS256)
  • Argon2 password hashing
  • Create, read, update, and delete personal notes
  • Paginated note listing (sorted by creation date descending)
  • Request validation on all inputs
  • Consistent JSON error responses
  • Health check endpoint
  • Swagger UI at /swagger-ui
  • OpenAPI JSON spec at /api/docs/openapi.json
  • Structured logging with tracing
  • PostgreSQL database with migration scripts
  • Docker Compose for local development
  • Multi-stage Dockerfile for production builds

Tech Stack

Category Technology Purpose
Language Rust 2021 Systems programming language
Web Framework Axum 0.7 Async HTTP framework
Runtime Tokio 1 (full features) Async runtime
Database PostgreSQL 16 Relational database
ORM SeaORM 1 Async database ORM
Auth JSON Web Token (jsonwebtoken 9) Token-based authentication
Hashing Argon2 0.5 Password hashing
Serialization Serde 1 JSON serialization/deserialization
Validation Validator 0.18 Request payload validation
Error Handling ThisError 2 Ergonomic error type definitions
Logging Tracing 0.1 + tracing-subscriber Structured logging
OpenAPI Utoipa 5 + utoipa-swagger-ui 8 API documentation
Middleware Tower 0.4 + tower-http 0.5 CORS, tracing middleware
Deployment Docker + Docker Compose Containerization

Architecture

Request Flow

The following diagram shows how an HTTP request flows through the application:

sequenceDiagram
    participant Client as Client (Browser/cURL)
    participant Router as Axum Router
    participant Middleware as Auth Middleware
    participant Controller as Controller
    participant Service as Service
    participant DB as PostgreSQL

    Client->>Router: HTTP Request
    Router->>Middleware: Pass through auth middleware (if route is protected)
    Middleware->>Middleware: Extract and validate JWT from Authorization header
    Middleware->>Router: Attach AuthUser to request extensions
    
    Router->>Controller: Route to handler with extracted parameters
    Controller->>Service: Call service with domain data
    Service->>DB: Query/Modify database via SeaORM
    DB-->>Service: Return result
    Service-->>Controller: Return domain result
    Controller-->>Router: Convert to HTTP response (JSON)
    Router-->>Client: HTTP Response
Loading

Folder Structure

rust-notes-api/
|
|-- src/
|   |-- main.rs              # Application entrypoint, server startup
|   |-- config.rs             # Environment variable configuration
|   |-- database.rs           # Database connection with retry logic
|   |-- errors.rs             # Global error handling (AppError)
|   |-- migration.rs          # SQL table creation migrations
|   |-- docs.rs               # OpenAPI documentation definition
|   |-- app_state.rs          # Shared application state
|   |
|   |-- entities/             # SeaORM entity models
|   |   |-- user.rs           # User model
|   |   |-- note.rs           # Note model
|   |   |-- mod.rs
|   |
|   |-- dto/                  # Data Transfer Objects
|   |   |-- auth.rs           # Register, Login, AuthResponse DTOs
|   |   |-- note.rs           # Create, Update, NoteResponse, Pagination DTOs
|   |   |-- mod.rs
|   |
|   |-- controllers/          # HTTP request handlers
|   |   |-- auth_controller.rs    # Auth endpoint handlers
|   |   |-- note_controller.rs    # Note CRUD endpoint handlers
|   |   |-- mod.rs
|   |
|   |-- services/             # Business logic layer
|   |   |-- auth_service.rs   # Registration and login logic
|   |   |-- note_service.rs   # Note CRUD logic with pagination
|   |   |-- mod.rs
|   |
|   |-- middleware/           # Request middleware
|   |   |-- auth.rs           # JWT authentication middleware
|   |   |-- mod.rs
|   |
|   |-- routes/               # Route group definitions
|   |   |-- auth_routes.rs    # Auth route grouping
|   |   |-- note_routes.rs    # Note route grouping
|   |   |-- mod.rs
|   |
|   |-- utils/                # Helper utilities
|       |-- auth.rs           # Password hashing, JWT creation/validation
|       |-- mod.rs
|
|-- Cargo.toml                # Rust dependency manifest
|-- Cargo.lock                # Locked dependency versions
|-- Dockerfile                # Multi-stage Docker build
|-- docker-compose.yml        # Docker Compose setup (PostgreSQL + API)
|-- .env                      # Local environment variables
|-- .env.example              # Example environment file
|-- .dockerignore             # Docker build ignore rules
|-- .gitignore                # Git ignore rules

Database Schema

erDiagram
    users {
        int id PK "Auto-increment"
        varchar email "Unique"
        text password_hash
        timestamp created_at
        timestamp updated_at
    }
    
    notes {
        int id PK "Auto-increment"
        int user_id FK "References users.id"
        varchar title
        text content
        timestamp created_at
        timestamp updated_at
    }
    
    users ||--o{ notes : "has many"
Loading

Data Flow for Note Creation

flowchart TD
    A["Client: POST /api/notes"] --> B["Auth Middleware: validate JWT"]
    B --> C{"JWT Valid?"}
    C -->|"No"| D["401 Unauthorized"]
    C -->|"Yes"| E["Extract user_id from token"]
    E --> F["Controller: validate request body"]
    F --> G{"Valid?"}
    G -->|"No"| H["400 Bad Request"]
    G -->|"Yes"| I["Service: create note in database"]
    I --> J["Insert into notes table\n(user_id, title, content)"]
    J --> K["Return created note as JSON"]
Loading

API Endpoints

Health

Method Path Description Auth Required
GET /health Health check No

Authentication

Method Path Description Auth Required
POST /api/auth/register Register new user No
POST /api/auth/login Login user No
GET /api/me Get current user Yes

Notes

Method Path Description Auth Required
GET /api/notes List notes (paginated) Yes
POST /api/notes Create a note Yes
GET /api/notes/:id Get a note by ID Yes
PUT /api/notes/:id Update a note Yes
DELETE /api/notes/:id Delete a note Yes

Documentation

Method Path Description Auth Required
GET /swagger-ui Swagger UI No
GET /api/docs/openapi.json OpenAPI JSON spec No

Getting Started

Prerequisites

  • Rust 2021 edition (1.75 or later)
  • Docker and Docker Compose (for PostgreSQL and containerized deployment)
  • Cargo (included with Rust)

Local Development

1. Clone the repository

git clone <repository-url>
cd rust-notes-api

2. Set up environment variables

cp .env.example .env
# Edit .env if needed (defaults work for local development)

3. Start PostgreSQL with Docker

docker compose up -d postgres

This starts a PostgreSQL 16 container on port 5432 with:

  • Username: postgres
  • Password: postgres
  • Database: rust_notes_api

4. Run the application

cargo run

The server starts at http://0.0.0.0:3000. Database migrations run automatically on startup.

5. Access Swagger UI

Open http://localhost:3000/swagger-ui in your browser to explore and test the API interactively.

Running with Docker (Full Stack)

docker compose up --build

This builds the API container and starts both PostgreSQL and the API service. The API is available at http://localhost:3000.

Testing the API

Register a user

curl -X POST http://localhost:3000/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "securePassword123"}'

Login

curl -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "securePassword123"}'

Save the returned token value.

Create a note

curl -X POST http://localhost:3000/api/notes \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{"title": "My first note", "content": "Hello, world!"}'

List notes (paginated)

curl "http://localhost:3000/api/notes?page=1&limit=10" \
  -H "Authorization: Bearer <your-token>"

Get a note

curl http://localhost:3000/api/notes/1 \
  -H "Authorization: Bearer <your-token>"

Update a note

curl -X PUT http://localhost:3000/api/notes/1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{"title": "Updated title", "content": "Updated content"}'

Delete a note

curl -X DELETE http://localhost:3000/api/notes/1 \
  -H "Authorization: Bearer <your-token>"

Health check

curl http://localhost:3000/health

Environment Variables

Variable Required Default Description
DATABASE_URL Yes - PostgreSQL connection string
JWT_SECRET Yes - Secret key for JWT signing
JWT_EXPIRATION_DAYS No 7 JWT token expiration in days
HOST No 0.0.0.0 Server bind address
PORT No 3000 Server port
RUST_LOG No - Logging verbosity (e.g., debug)

Project Structure Details

Layer Responsibilities

Layer Responsibility Examples
Routes Define URL paths and HTTP method mappings /api/notes -> GET -> list
Controllers Extract request data, call services, format responses Parse JSON body, call service
Services Implement business logic and database queries Register user, create note
Middleware Process requests before/after handlers JWT validation, logging
DTOs Define request/response shapes and validation rules RegisterDto, CreateNoteDto
Entities Map database tables to Rust structs User, Note models

Error Handling

All errors flow through the AppError enum which implements Axum's IntoResponse trait:

Error Variant HTTP Status Description
ValidationError 400 Invalid input data
Unauthorized 401 Missing or invalid JWT
Forbidden 403 Insufficient permissions
NotFound 404 Resource does not exist
Conflict 409 Duplicate resource (e.g., email)
InternalServerError 500 Unexpected server failure

Response format:

{
    "error": {
        "message": "Validation error: email is required",
        "status": 400
    }
}

Possible Improvements (Version 2)

  • Refresh token rotation for enhanced auth security
  • Email verification flow on registration
  • Rate limiting to prevent brute force attacks
  • Role-based access control (RBAC)
  • Soft delete for notes with restore capability
  • Note sharing between users
  • Search and filtering by title/content
  • Sort order customization (by title, updated_at, etc.)
  • Automated integration tests
  • CI/CD pipeline with GitHub Actions
  • Health check endpoint with database connectivity check
  • Prometheus metrics endpoint
  • Database connection pooling tuning
  • Request ID tracing across middleware and logs

License

MIT

About

A production-style REST API for managing personal notes. Built with Rust, Axum, and PostgreSQL. Features JWT-based authentication, pagination, OpenAPI documentation with Swagger UI, and Docker support.

Resources

Stars

Watchers

Forks

Contributors

Languages