spikard 0.15.3

High-performance HTTP framework built on Axum and Tower-HTTP with type-safe routing, validation, WebSocket/SSE support, and lifecycle hooks
Documentation

Spikard

Rust-centric polyglot HTTP framework built on Axum and Tower-HTTP. Type-safe routing, JSON Schema validation, OpenAPI/AsyncAPI/GraphQL/JSON-RPC codegen, WebSocket/SSE, lifecycle hooks, and a tower-http middleware stack.

Installation

cargo add spikard

System Requirements

Quick Start

use axum::response::Json;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use spikard::{get, post, App, RequestContext};

#[derive(Serialize, Deserialize, JsonSchema)]
struct User {
    id: i64,
    name: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut app = App::new();

    app.route(get("/users/:id"), |ctx: RequestContext| async move {
        let id = ctx.path_param("id").unwrap_or("0").parse::<i64>().unwrap_or_default();
        Ok(Json(User { id, name: "Alice".into() }).into())
    })?;

    app.route(
        post("/users").request_body::<User>().response_body::<User>(),
        |ctx: RequestContext| async move {
            let user: User = ctx.json()?;
            Ok(Json(user).into())
        },
    )?;

    app.run().await?;
    Ok(())
}

Features

  • HTTP routing — type-safe route definitions with path, query, and body parameter validation
  • OpenAPI / AsyncAPI / GraphQL / JSON-RPC — code generation and spec parsing built in
  • Tower middleware — compression, rate limiting, timeouts, auth (JWT/API key), static files
  • Lifecycle hooksonRequest, preValidation, preHandler, onResponse, onError
  • Fixture-driven testing — shared JSON fixtures drive tests across all language bindings
  • Polyglot — single Rust core, thin bindings for Python, Node.js, Ruby, PHP, Elixir, Go, Java, C#, Kotlin, Dart, Gleam, WASM, Swift, Zig, and C FFI

Routing

use spikard::prelude::*;

let mut app = App::new();

app.route(get("/health"), |_ctx: Context| async { Ok(Json(json!({"status": "ok"}))) })?;
app.route(post("/users"), |ctx: Context| async move {
    let user: serde_json::Value = ctx.json()?;
    Ok(Json(user))
})?;

Validation

use schemars::JsonSchema;
use serde::Deserialize;

#[derive(Deserialize, JsonSchema)]
struct Payment {
    id: String,
    amount: f64,
}

app.route(
    post("/payments").request_body::<Payment>().response_body::<Payment>(),
    |ctx: Context| async move {
        let payment: Payment = ctx.json()?;
        Ok(Json(payment))
    },
)?;

Middleware

use tower_http::trace::TraceLayer;

let mut app = App::new();
app.layer(TraceLayer::new_for_http());

Documentation

  • Repository — source code, examples, and contributing guide
  • Examples — working examples per language
  • Issues — bug reports and feature requests

Contributing

Contributions are welcome. See CONTRIBUTING.md.

License

MIT License — see LICENSE for details.