at-jet

Crates.ioat-jet
lib.rsat-jet
version0.4.0
created_at2026-01-09 14:35:04.160736+00
updated_at2026-01-15 06:48:17.591218+00
descriptionHigh-performance HTTP + Protobuf API framework for mobile services
homepage
repository
max_upload_size
id2032191
size190,903
Junfei Wang (Junfei-Wang_astg)

documentation

README

AT-Jet

High-performance HTTP + Protobuf API framework for mobile services.

Not just a wrapper - AT-Jet is an opinionated, production-ready foundation for mobile API development. See Architecture Rationale for why this project exists.

Why AT-Jet?

Building mobile APIs with Protobuf over HTTP requires solving the same problems repeatedly:

  • Content-type negotiation
  • Request body size limits
  • Consistent error handling
  • Client library generation
  • Team coding conventions

Without AT-Jet (30+ lines per handler):

async fn create_user(headers: HeaderMap, body: Bytes) -> impl IntoResponse {
    // Check content-type... validate size... decode proto... handle errors...
}

With AT-Jet (5 lines):

async fn create_user(ProtobufRequest(req): ProtobufRequest<CreateUserRequest>) -> ProtobufResponse<User> {
    ProtobufResponse::ok(User { id: 1, name: req.name })
}

Features

  • HTTP/1.1 and HTTP/2 support via axum
  • Protobuf request/response handling with automatic content negotiation
  • Dual-format support - Protobuf for production, JSON for debugging (with key authorization)
  • CDN-friendly design for global mobile users
  • Middleware support for authentication, logging, compression
  • Type-safe routing with compile-time guarantees
  • Efficient bandwidth - Protobuf is 60-70% smaller than JSON
  • Schema evolution - Protobuf handles backward/forward compatibility

Quick Start

Add to your Cargo.toml:

[dependencies]
at-jet = "0.3"
tokio = { version = "1", features = ["full"] }
prost = "0.13"

[build-dependencies]
prost-build = "0.13"

See Quick Start Guide for a complete 5-minute tutorial.

Server Example

use at_jet::prelude::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let server = JetServer::new()
        .route("/api/users", get(list_users).post(create_user))
        .route("/api/users/:id", get(get_user))
        .with_cors()
        .with_compression();

    server.serve("0.0.0.0:8080").await?;
    Ok(())
}

async fn get_user(Path(id): Path<i32>) -> ProtobufResponse<User> {
    let user = User { id, name: "John".to_string() };
    ProtobufResponse::ok(user)
}

async fn list_users() -> ProtobufResponse<ListUsersResponse> {
    // Return list of users
    ProtobufResponse::ok(response)
}

async fn create_user(
    ProtobufRequest(req): ProtobufRequest<CreateUserRequest>
) -> ProtobufResponse<User> {
    // Create user from request
    ProtobufResponse::created(user)
}

Client Example

use at_jet::prelude::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Protobuf client (production)
    let client = JetClient::new("https://api.example.com")?;

    // GET request
    let user: User = client.get("/api/users/123").await?;

    // POST request
    let request = CreateUserRequest { name: "John".to_string() };
    let created: User = client.post("/api/users", &request).await?;

    // JSON debug client (for development)
    let debug_client = JetClient::builder()
        .base_url("https://api.example.com")
        .debug_key("dev-debug-key")
        .build()?;

    // JSON requests for debugging
    let user_json: UserJson = debug_client.get_json("/api/users/123").await?;
    let raw_json = debug_client.get_json_raw("/api/users").await?;
    println!("Response: {}", raw_json);

    Ok(())
}

Dual-Format Support (Protobuf + JSON)

AT-Jet supports both Protobuf (production) and JSON (debugging) formats. JSON requires authorization via debug keys to prevent accidental use in production.

Why Require Authorization for JSON?

Protobuf provides schema evolution guarantees that JSON lacks:

  • Field numbers enable backward/forward compatibility
  • Unknown fields are preserved during deserialization
  • Optional fields have well-defined defaults

If clients accidentally use JSON in production, they lose these guarantees and may break when the schema evolves. The debug key requirement ensures JSON is only used intentionally.

Configuring Debug Keys

use at_jet::prelude::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Configure authorized debug keys (call once at startup)
    configure_debug_keys(vec![
        "alice-dev-key".to_string(),
        "bob-dev-key".to_string(),
        "qa-team-key".to_string(),
    ]);

    // Or disable JSON completely (production default)
    // configure_debug_keys(vec![]);

    let server = JetServer::new()
        .route("/api/users", post(create_user))
        .with_cors();

    server.serve("0.0.0.0:8080").await?;
    Ok(())
}

Using Dual-Format Handlers

use at_jet::prelude::*;

// Dual-format handler - accepts both Protobuf and JSON
async fn create_user(
    ApiRequest { body, format }: ApiRequest<CreateUserRequest>
) -> ApiResponse<User> {
    let user = User { id: 1, name: body.name };
    ApiResponse::ok(format, user)  // Response format matches Accept header
}

Client Usage

# Protobuf request (production - no debug key needed)
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/x-protobuf" \
  -H "Accept: application/x-protobuf" \
  --data-binary @request.pb

# JSON request (debugging - requires valid debug key)
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "X-Debug-Format: alice-dev-key" \
  -d '{"name": "John"}'

# JSON request without debug key → rejected with 415 Unsupported Media Type
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John"}'

Format Selection Rules

Request Format Response Format Condition
Protobuf Protobuf Default (production)
JSON JSON Valid X-Debug-Format header
JSON Error 415 Missing/invalid debug key
Protobuf JSON Accept: application/json + valid debug key

Architecture

Mobile Clients (iOS, Android, Web)
        │
        ▼
   CDN (Global)
        │
        ▼
  ┌─────────────┐
  │   AT-Jet    │  ◄── HTTP + Protobuf
  │   Server    │
  └─────────────┘
        │
        ▼
  ┌─────────────┐
  │  Backend    │  ◄── ZUS-RS (internal RPC)
  │  Services   │
  └─────────────┘

Why HTTP + Protobuf?

Factor JSON Protobuf
Size 100% 30-40% (60-70% smaller)
Parse Speed 100% 10-20% (5-10x faster)
Schema Evolution Manual Built-in
Type Safety Runtime Compile-time

Running Examples

# Start server
cargo run --example basic_server

# In another terminal, run client
cargo run --example basic_client

Documentation

License

MIT OR Apache-2.0

Commit count: 0

cargo fmt