lmrc-http-common

Crates.iolmrc-http-common
lib.rslmrc-http-common
version0.3.16
created_at2025-11-30 15:53:29.874656+00
updated_at2025-12-11 13:28:11.302709+00
descriptionCommon HTTP utilities and patterns for LMRC Stack applications
homepage
repositoryhttps://gitlab.com/lemarco/lmrc-stack
max_upload_size
id1958407
size130,157
Le Marc (lemarco)

documentation

README

lmrc-http-common

Common HTTP utilities and patterns for LMRC Stack applications.

This library provides reusable components for building Axum-based HTTP services with best practices built-in.

Features

  • Error Handling: Standard HTTP error types with automatic response conversion
  • Response Wrappers: Success, created, empty, and paginated response types
  • Middleware: CORS, logging, request ID, and more
  • Authentication (optional): JWT, password hashing, session management
  • Configuration Management: Server and database configuration loading
  • Health Checks: Standardized health check framework
  • Validated Extractors (optional): Auto-validate requests with validator crate
  • Server Bootstrap (optional): Quick server setup with tracing and configuration

Installation

Add to your Cargo.toml:

[dependencies]
lmrc-http-common = "0.3.11"

Feature Flags

  • auth (default) - Authentication utilities (JWT, bcrypt, sessions)
  • validation (default) - Request validation helpers
  • server - Server bootstrap utilities (requires tracing-subscriber, dotenvy)

To enable all features:

[dependencies]
lmrc-http-common = { version = "0.3.11", features = ["server"] }

Quick Start

Basic Handler with Error Handling

use lmrc_http_common::{
    error::{HttpError, HttpResult},
    response::SuccessResponse,
};
use axum::{Router, routing::get, Json};

async fn get_user(id: u32) -> HttpResult<Json<SuccessResponse<User>>> {
    let user = database
        .find_user(id)
        .await
        .ok_or_else(|| HttpError::NotFound(format!("User {} not found", id)))?;

    Ok(Json(SuccessResponse::new(user)))
}

Configuration Loading

use lmrc_http_common::config::{ServerConfig, DatabaseConfig};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Load configuration from environment variables
    let server_config = ServerConfig::from_env()?;
    let db_config = DatabaseConfig::from_env(None)?;

    println!("Starting server on {}", server_config.bind_addr()?);
    Ok(())
}

Health Checks

use lmrc_http_common::health::{HealthChecker, HealthCheck, CheckResult};
use std::sync::Arc;
use async_trait::async_trait;

struct DatabaseHealthCheck {
    db: DatabaseConnection,
}

#[async_trait]
impl HealthCheck for DatabaseHealthCheck {
    async fn check(&self) -> CheckResult {
        match self.db.ping().await {
            Ok(_) => CheckResult::healthy_with_message("Database connected"),
            Err(e) => CheckResult::unhealthy(format!("Database error: {}", e)),
        }
    }

    fn name(&self) -> &str {
        "database"
    }
}

// In your router setup:
let checker = Arc::new(
    HealthChecker::new(env!("CARGO_PKG_VERSION"))
        .add_check(Arc::new(DatabaseHealthCheck { db }))
);

let app = Router::new()
    .route("/health", get(lmrc_http_common::health::health_handler))
    .with_state(checker);

Validated Request Extractors

use lmrc_http_common::extractors::ValidatedJson;
use serde::Deserialize;
use validator::Validate;

#[derive(Deserialize, Validate)]
struct CreateUser {
    #[validate(length(min = 3, max = 50))]
    username: String,
    #[validate(email)]
    email: String,
}

async fn create_user(
    ValidatedJson(payload): ValidatedJson<CreateUser>
) -> &'static str {
    // payload is automatically validated!
    // Returns 422 Unprocessable Entity if validation fails
    "User created"
}

Server Bootstrap (with server feature)

use axum::{Router, routing::get};
use lmrc_http_common::server::ServerBootstrap;

#[derive(Clone)]
struct AppState {
    config: Config,
    db: DatabaseConnection,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let state = AppState {
        config: Config::from_env()?,
        db: DatabaseConnection::new().await?,
    };

    ServerBootstrap::with_state(state)
        .with_tracing("myapp")
        .with_port(8080)
        .with_router(|state| {
            Router::new()
                .route("/health", get(|| async { "OK" }))
                .with_state(state)
        })
        .serve()
        .await
}

Or use the quick start helper:

use axum::{Router, routing::get};
use lmrc_http_common::server::quick_start;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let router = Router::new().route("/health", get(|| async { "OK" }));
    quick_start("myapp", router, 8080).await
}

Module Overview

error

Standard HTTP error types that automatically convert to appropriate HTTP responses:

  • HttpError::BadRequest(String) → 400
  • HttpError::Unauthorized(String) → 401
  • HttpError::Forbidden(String) → 403
  • HttpError::NotFound(String) → 404
  • HttpError::ValidationError(String) → 422
  • HttpError::InternalServer(String) → 500

Use the app_error! macro to create custom error types:

use lmrc_http_common::app_error;

app_error! {
    MyAppError {
        BusinessLogic(String),
        ExternalApi(String),
    }
}

response

Standard response wrappers:

  • SuccessResponse<T> - Standard success response with data
  • CreatedResponse<T> - 201 Created with location header
  • EmptyResponse - 204 No Content
  • PaginatedResponse<T> - Paginated list with metadata

middleware

Reusable middleware layers:

  • add_request_id - Adds unique request ID to each request
  • log_request - Logs all requests with duration
  • cors_with_origins(Vec<String>) - CORS with specific origins

config

Configuration management:

  • ServerConfig - Host, port, CORS origins
  • DatabaseConfig - Database URL, connection pool settings
  • ConfigLoader trait - For custom configuration types

health

Health check framework:

  • HealthStatus - Overall application health
  • HealthCheck trait - Implement for custom checks
  • HealthChecker - Aggregates multiple health checks
  • health_handler - Axum handler for health endpoint

auth (requires auth feature)

Authentication utilities:

  • jwt - JWT token creation and verification
  • password - Password hashing and verification (bcrypt)
  • session - Session management

extractors (requires validation feature)

Auto-validating request extractors:

  • ValidatedJson<T> - JSON with automatic validation
  • ValidatedQuery<T> - Query parameters with validation

server (requires server feature)

Server bootstrap utilities:

  • ServerBootstrap - Fluent API for server setup
  • quick_start - Simple one-liner server start

Examples

See the examples directory for complete working examples:

  • gateway - API gateway with routing and auth
  • api-service-template - Standard REST API template
  • infra-api - Infrastructure management API

Development

Running Tests

cargo test -p lmrc-http-common --all-features

Building Documentation

cargo doc --open -p lmrc-http-common --all-features

License

Dual licensed under MIT OR Apache-2.0 (your choice).

Contributing

This library is part of the LMRC Stack monorepo.

See the main repository for contribution guidelines.

Commit count: 0

cargo fmt