A production-ready newsletter subscription API built with Rust, Actix-web, and PostgreSQL. This project follows the "Zero to Production in Rust" book methodology to build a robust, testable, and maintainable backend service.
- Health Check Endpoint: Monitor service availability
- Subscription Management: RESTful API for newsletter subscriptions
- Database Integration: PostgreSQL with SQLx for type-safe queries
- Configuration Management: YAML-based configuration with environment-specific settings
- Structured Logging: Comprehensive tracing with
tracingcrate - CI/CD Pipeline: GitHub Actions for testing, linting, and code coverage
- Database Migrations: Version-controlled schema management with SQLx
- Security: Secure password handling with
secrecycrate
- Rust: 2024 edition
- Web Framework: Actix-web 4
- Database: PostgreSQL with SQLx
- Configuration:
configcrate with YAML support - Logging:
tracing,tracing-subscriber,tracing-bunyan-formatter - Testing: Integration tests with isolated databases
- CI/CD: GitHub Actions
zero2prod/
├── src/
│ ├── main.rs # Application entry point
│ ├── lib.rs # Library exports
│ ├── configuration.rs # Configuration management
│ ├── telemetry.rs # Logging and tracing setup
│ ├── startup.rs # Application startup logic
│ └── routes/
│ ├── mod.rs # Routes module
│ ├── health_check.rs # Health check endpoint
│ └── subscriptions.rs # Subscription endpoints
├── tests/
│ └── health_check.rs # Integration tests
├── migrations/
│ └── 20260208125623_create_subscriptions_table.sql
├── scripts/
│ └── init_db.sh # Database initialization script
├── .github/workflows/
│ └── general.yml # CI/CD pipeline
├── configuration.yaml # Application configuration
├── Cargo.toml # Rust dependencies
└── Cargo.lock # Dependency lock file
- Rust (latest stable version)
- PostgreSQL 14+
- SQLx CLI (
cargo install sqlx-cli)
-
Clone the repository:
git clone <repository-url> cd zero2prod
-
Set up the database:
./scripts/init_db.sh
Or manually:
# Start PostgreSQL (if using Docker) docker run --name zero2prod-postgres \ -e POSTGRES_USER=postgres \ -e POSTGRES_PASSWORD=password \ -e POSTGRES_DB=newsletter \ -p 5432:5432 \ -d postgres:14 # Run migrations export DATABASE_URL=postgres://postgres:password@localhost:5432/newsletter sqlx database create sqlx migrate run
-
Configure the application:
cp configuration.yaml.example configuration.yaml # Edit configuration.yaml with your settings -
Build and run:
cargo build --release cargo run
The application will start on
http://127.0.0.1:8000
The application uses configuration.yaml for settings:
application_port: 8000
database:
host: "127.0.0.1"
port: 5432
username: "postgres"
password: "password"
database_name: "newsletter"- GET
/health_check - Returns:
200 OKwith empty body - Purpose: Service health monitoring
- POST
/subscriptions - Content-Type:
application/x-www-form-urlencoded - Request body:
{ "name": "John Doe", "email": "john@example.com" } - Returns:
200 OKon success,400 Bad Requestfor invalid data,500 Internal Server Errorfor database failures - Purpose: Create a new newsletter subscription
# Run all tests
cargo test
# Run tests with logging
TEST_LOG=true cargo test
# Run specific test
cargo test health_check_works- Isolated Databases: Each test runs with a unique database
- Structured Logging: Optional test logging with
TEST_LOGenvironment variable - Integration Tests: Full HTTP request/response testing
- Database Assertions: Verify data persistence
# Create new migration
sqlx migrate add <migration_name>
# Run migrations
sqlx migrate run
# Revert migration
sqlx migrate revert# Format code
cargo fmt
# Lint code
cargo clippy -- -D warnings
# Check formatting
cargo fmt --checkThe application uses structured logging with the tracing crate. Logs include:
- Request/response information
- Database query execution
- Error details with context
- Performance metrics
The GitHub Actions workflow includes:
- Test Job: Runs tests with PostgreSQL service container
- Format Check: Ensures code follows Rustfmt standards
- Code Coverage: Generates coverage reports with
cargo-llvm-cov
- Password Security: Database passwords are stored as
SecretStringtypes - Input Validation: Basic validation for subscription data
- SQL Injection Prevention: SQLx provides compile-time query validation
- Error Handling: Generic error responses to avoid information leakage
cargo build --releaseThe optimized binary will be available at target/release/zero2prod
DATABASE_URL: PostgreSQL connection stringRUST_LOG: Logging level (default:info)
FROM rust:latest as builder
WORKDIR /usr/src/zero2prod
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y libssl3 ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/src/zero2prod/target/release/zero2prod /usr/local/bin/zero2prod
COPY configuration.yaml /etc/zero2prod/configuration.yaml
EXPOSE 8000
CMD ["zero2prod"]- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Based on the "Zero to Production in Rust" book by Luca Palmieri
- Built with the amazing Rust ecosystem
- Inspired by production-ready backend patterns
For issues, questions, or contributions:
- Check existing issues
- Create a new issue with detailed information
- Include reproduction steps for bugs
Note: This is a learning project following production-ready patterns. Use as a reference for building Rust web applications.