A comprehensive Rust web API foundation library providing reusable patterns and utilities for building consistent, maintainable web APIs.
DateRangeQuery- Simple date-based filtering (YYYY-MM-DD format)DateTimeRangeQuery- Precise datetime filtering with timezone support (RFC 3339)PaginationQuery- Page-based pagination with metadataSortQuery- Flexible multi-field sorting with SQL generation
ApiResponse<T>- Standardized JSON response formatPaginatedData<T>- Paginated response wrapper with metadata- Response macros - 
data!(),empty!()for quick responses 
AppError- Comprehensive error types for web applications- Unified HTTP 200 responses - All responses return HTTP 200 with business codes in JSON
 - Business code mapping - Errors map to semantic business codes (SUCCESS, VALIDATION_ERROR, etc.)
 - Validation integration - Seamless validator crate integration
 
ValidatedJson<T>- JSON extractor with automatic validation- Custom validators - Password strength, phone numbers, email, etc.
 - Query validation - Built-in validation for all query parameter types
 
- Middleware helpers - CORS, request ID, tracing integration
 - OpenAPI support - Full utoipa integration with examples
 - Feature flags - Optional dependencies (axum, sqlx, jwt)
 
Add this to your Cargo.toml:
[dependencies]
avinapi = "0.1.0"
# Optional features
avinapi = { version = "0.1.0", features = ["axum", "sqlx", "jwt"] }axum(default) - Axum web framework integrationsqlx(default) - Database integration utilitiesjwt(default) - JWT authentication helpers
use avinapi::prelude::*;
use axum::{Router, extract::Query, routing::get};
#[derive(serde::Serialize)]
struct User {
    id: u32,
    name: String,
    email: String,
}
// Simple pagination endpoint
async fn list_users(
    Query(pagination): Query<PaginationQuery>,
) -> JsonResult<PaginatedData<User>> {
    let users = get_users_from_db(
        pagination.get_limit(),
        pagination.get_offset(),
    ).await?;
    
    let total_count = count_users().await?;
    let response = PaginatedData::new(users, &pagination, total_count);
    
    data!(response)
}
// Advanced filtering with multiple query parameters
async fn list_orders(
    Query(pagination): Query<PaginationQuery>,
    Query(date_range): Query<DateTimeRangeQuery>,
    Query(sort): Query<SortQuery>,
) -> JsonResult<PaginatedData<Order>> {
    // Validate datetime range (max 30 days)
    date_range.validate_max_duration(30)?;
    
    // Parse to UTC for database queries
    let start_utc = date_range.parse_start_utc()?;
    let end_utc = date_range.parse_end_utc()?;
    
    // Generate SQL ORDER BY clause
    let order_clause = sort.to_sql_with_prefix("orders");
    
    let orders = query_orders(start_utc, end_utc, order_clause, pagination).await?;
    data!(orders)
}
fn main() {
    let app = Router::new()
        .route("/users", get(list_users))
        .route("/orders", get(list_orders));
    
    // ... run server
}// URL: /reports?start_date=2024-01-01&end_date=2024-12-31
async fn reports(Query(date_range): Query<DateRangeQuery>) -> JsonResult<Vec<Report>> {
    let reports = Report::find_by_date_range(
        date_range.start_date,
        date_range.end_date
    ).await?;
    
    data!(reports)
}// URL: /events?start_datetime=2024-12-19T10:30:00+08:00&end_datetime=2024-12-19T18:00:00+08:00
async fn events(Query(datetime_range): Query<DateTimeRangeQuery>) -> JsonResult<Vec<Event>> {
    // Validate range
    datetime_range.validate_range()?;
    datetime_range.validate_max_duration(7)?; // Max 7 days
    
    // Parse to UTC (handles timezone conversion automatically)
    let start_utc = datetime_range.parse_start_utc()?;
    let end_utc = datetime_range.parse_end_utc()?;
    
    let events = Event::find_by_datetime_range(start_utc, end_utc).await?;
    data!(events)
}start_date=2024-12-19- Date only formatend_date=2024-12-31- Perfect for daily/monthly reports
start_datetime=2024-12-19T10:30:00Z- UTC formatstart_datetime=2024-12-19T10:30:00+08:00- Timezone awarestart_datetime=2024-12-19T10:30:00-05:00- Negative timezone
use avinapi::{ValidatedJson, validation::*};
#[derive(Deserialize, Validate, ToSchema)]
struct CreateUserRequest {
    #[validate(length(min = 1, max = 100))]
    name: String,
    
    #[validate(email)]
    email: String,
    
    #[validate(custom = "validate_password_strength")]
    password: String,
}
async fn create_user(
    ValidatedJson(request): ValidatedJson<CreateUserRequest>
) -> JsonResult<User> {
    // Request is guaranteed to be valid here
    let user = User::create(request.name, request.email, request.password).await?;
    data!(user)
}Important: This library follows a unified response pattern where all endpoints return HTTP 200 status codes, with business logic status indicated by the code field in the JSON response body.
All endpoints return a consistent JSON structure:
{
  "code": "SUCCESS",           // Business status code
  "data": { ... },            // Response data
  "message": null             // Optional message
}Error responses (still HTTP 200):
{
  "code": "VALIDATION_ERROR", // Business error code
  "data": null,
  "message": "name: Name is required, email: Invalid email format"
}SUCCESS- Operation completed successfullyVALIDATION_ERROR- Input validation failedAUTHENTICATION_ERROR- Authentication required or failedAUTHORIZATION_ERROR- Insufficient permissionsNOT_FOUND- Requested resource not foundCONFLICT- Resource conflict (e.g., duplicate email)INTERNAL_ERROR- Server-side errorDATABASE_ERROR- Database operation failedNETWORK_ERROR- External service call failed
Paginated responses:
{
  "code": "SUCCESS",
  "data": {
    "data": [...],
    "meta": {
      "current_page": 1,
      "per_page": 20,
      "total_items": 150,
      "total_pages": 8,
      "has_next_page": true,
      "has_prev_page": false
    }
  },
  "message": null
}# Minimal setup
avinapi = { version = "0.1.0", default-features = false }
# With specific features
avinapi = { version = "0.1.0", features = ["axum", "sqlx"] }
# Full features
avinapi = { version = "0.1.0", features = ["axum", "sqlx", "jwt"] }The library respects these environment variables:
RUST_LOG- Logging level (uses tracing)DATABASE_URL- Database connection (when using sqlx feature)
avinapi/
βββ src/
β   βββ error/          # Error handling and HTTP status mapping
β   βββ middleware/     # Common middleware utilities
β   βββ query/          # Query parameter types and validation
β   β   βββ date_range.rs      # Simple date filtering
β   β   βββ datetime_range.rs  # Precise datetime filtering
β   β   βββ pagination.rs     # Page-based pagination
β   β   βββ sort.rs           # Multi-field sorting
β   βββ response/       # Standardized response types
β   βββ validation/     # JSON validation and custom validators
β   βββ prelude.rs     # Common imports
βββ examples/          # Usage examples
βββ tests/            # Integration tests
Run the included examples:
# Basic query parameter usage
cargo run --example query_parameters
# DateTime range handling with different formats
cargo run --example datetime_range_usageThen visit:
http://localhost:3000/users?page=1&per_page=10http://localhost:3000/calendar?start_datetime=2024-12-19T10:30:00+08:00
use avinapi::prelude::*;
use axum::{Router, middleware};
let app = Router::new()
    .route("/api/users", get(list_users))
    .layer(middleware::from_fn(request_id_middleware))
    .layer(cors_layer());use avinapi::query::*;
use sqlx::{PgPool, query_as};
async fn get_orders(
    pool: &PgPool,
    datetime_range: &DateTimeRangeQuery,
    pagination: &PaginationQuery,
) -> Result<Vec<Order>, sqlx::Error> {
    let (start_utc, end_utc) = datetime_range.parse_utc_range();
    
    query_as!(
        Order,
        r#"
        SELECT * FROM orders 
        WHERE ($1::timestamptz IS NULL OR created_at >= $1)
          AND ($2::timestamptz IS NULL OR created_at < $2)
        ORDER BY created_at DESC
        LIMIT $3 OFFSET $4
        "#,
        start_utc,
        end_utc,
        pagination.get_limit() as i64,
        pagination.get_offset() as i64
    )
    .fetch_all(pool)
    .await
}# Run all tests
cargo test
# Run with all features
cargo test --all-features
# Run examples
cargo test --examples
# Run doc tests
cargo test --docThis project follows Semantic Versioning:
- MAJOR version for incompatible API changes
 - MINOR version for backwards-compatible functionality additions
 - PATCH version for backwards-compatible bug fixes
 
Contributions are welcome! Please feel free to submit a Pull Request.
git clone https://github.com/AvinasiLabs/avinapi
cd avinapi
cargo build --all-features
cargo test --all-featuresThis project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
 - MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
 
at your option.
- Axum - Modern web framework
 - Chrono - Date and time library
 - Serde - Serialization framework
 - Validator - Data validation
 - utoipa - OpenAPI documentation
 
Created by @lilhammer111 | Latte Team, Avinasi Labs