atrg-core 0.1.1

Core framework: AppState, config, app builder for at-rust-go
Documentation

atrg-core

The spine of the at-rust-go framework — app builder, configuration, shared state, and error types.

Part of at-rust-go (atrg) — a batteries-included AT Protocol backend framework for Rust.

What this crate provides

  • AtrgApp — the main application builder. Chain .mount() to add Axum routers, .on_event() to register Jetstream handlers, and .run() to start the server.
  • Config — strongly-typed configuration loaded from atrg.toml at startup (app settings, auth, database, Jetstream, identity).
  • AppState — the shared state bundle (Arc-wrapped) passed into every Axum handler. Holds the config, database pool, HTTP client, and identity resolver.
  • AtrgError / AtrgResult — framework-wide error type that serializes to JSON automatically ({ "error": "code", "message": "..." }).
  • RateLimiter / RateLimitConfig — configurable rate limiting for API endpoints.
  • shutdown_signal() — graceful shutdown listener (Ctrl+C / SIGTERM).
  • CORS, security headers, request IDs, health checks, and pagination — built-in middleware and utilities so you don't wire them yourself.

Usage

Add to your Cargo.toml:

[dependencies]
atrg-core = "0.1"

Minimal application:

use atrg_core::AtrgApp;
use axum::{Router, routing::get, Json};
use serde_json::json;

fn api() -> Router<atrg_core::AppState> {
    Router::new()
        .route("/", get(|| async { Json(json!({ "status": "ok" })) }))
}

#[tokio::main]
async fn main() -> atrg_core::AtrgResult<()> {
    AtrgApp::new()
        .mount(api())
        .run()
        .await
}

This loads atrg.toml, connects to SQLite, runs migrations, mounts OAuth routes, applies CORS + security headers, and starts serving — all in one call.

Error handling in handlers

use atrg_core::{AppState, AtrgError};
use axum::{extract::State, Json};

async fn get_item(
    State(state): State<AppState>,
) -> Result<Json<serde_json::Value>, AtrgError> {
    let row = sqlx::query!("SELECT name FROM items LIMIT 1")
        .fetch_optional(&state.db)
        .await?;

    match row {
        Some(r) => Ok(Json(serde_json::json!({ "name": r.name }))),
        None => Err(AtrgError::NotFound),
    }
}

AtrgError variants (NotFound, BadRequest, Auth, Database, Internal) each map to the correct HTTP status code and a JSON error body.

Modules

Module Purpose
app AtrgApp builder and run() implementation
config Config and sub-structs deserialized from atrg.toml
state AppState — the shared context for all handlers
error AtrgError, AtrgResult
cors CORS layer built from [app].cors_origins
security Security headers middleware (X-Content-Type-Options, X-Frame-Options, etc.)
health /healthz and /readyz endpoints
pagination Cursor-based pagination helpers
request_id Per-request ID generation and propagation
rate_limit RateLimiter and RateLimitConfig
shutdown shutdown_signal() for graceful termination
env_override Environment variable overrides for config values

License

LGPL-3.0-only — see LICENSE.