Tako v.0.5.0 road to v.1.0.0

by Daniel Boros

Nov 11

3 min read

3 views

A lot has landed since we have introduced Tako at first, focused on performance, developer ergonomics, and production‑readiness: SIMD JSON, plugins (compression, CORS, rate limiting), GraphQL, improved routing, WebSockets/SSE/HTTP2/TLS, and more.

Live production OpenAPI service (stochastic simulation demo) running on Tako: https://stochastic-api-production.up.railway.app/

Benchmarks: SIMD JSON improvements

Real load against a heavy JSON endpoint showed a solid throughput gain after enabling SIMD‑accelerated JSON parsing.

Before SIMD

wrk -t4 -c100 -d15s -s post.lua http://localhost:8080/diffusion/gbm
Running 15s test @ http://localhost:8080/diffusion/gbm
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.37s   410.43ms   1.99s    59.09%
    Req/Sec     9.07      7.53    40.00     70.53%
  258 requests in 15.10s, 24.29GB read
  Socket errors: connect 0, read 0, write 0, timeout 236
Requests/sec:     17.09
Transfer/sec:      1.61GB

After enabling SIMD JSON

wrk -t4 -c100 -d15s -s post.lua http://localhost:8080/diffusion/gbm
Running 15s test @ http://localhost:8080/diffusion/gbm
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.36s   416.70ms   1.94s    63.27%
    Req/Sec    10.14      7.74    40.00     66.82%
  319 requests in 15.10s, 29.71GB read
  Socket errors: connect 0, read 0, write 0, timeout 270
Requests/sec:     21.12
Transfer/sec:      1.97GB

Summary: ~24% higher RPS and ~22% higher transfer/sec on a JSON‑heavy workload.

Major changes

  • SIMD‑accelerated JSON extractor (feature‑gated)
  • Plugin system with route‑level plugins
    • Compression (gzip, brotli, deflate, optional zstd; streaming; min‑size thresholds)
    • CORS (preflight, origins/methods/headers, credentials, max‑age)
    • Rate limiter (token bucket; per‑IP; refill/burst)
  • Async GraphQL integration (HTTP + subscriptions) and optional GraphiQL helper and even more a Generic Ws impl for ergonomics
  • Routing improvements: matchit router, TSR redirects, fallback handlers, memory optimizations
  • DX improvements: handler macro (multiple extractor arguments), Responder for anyhow::Result, redirect helpers
  • Realtime/media: WebSockets (incl. HTTP/2 example), SSE, file streaming, Range extractor
  • Security and formats: JWT extractors, Protobuf (feature), TLS backend

SIMD JSON extractor

High‑throughput JSON parsing for large payloads; usable as both extractor and responder.

use tako::extractors::simdjson::SimdJson;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct ApiResponse {
    success: bool,
    message: String,
}

async fn api_handler(SimdJson(request): SimdJson<ApiResponse>) -> SimdJson<ApiResponse> {
    // Process the request...
    SimdJson(ApiResponse {
        success: true,
        message: "Request processed successfully".to_string(),
    })
}

Plugins: compression, CORS, rate limiting

Apply globally or to specific routes.

Global compression (streaming brotli/gzip example):

router.plugin(
    CompressionBuilder::new()
      .enable_gzip(true)
      .enable_brotli(true)
      .enable_stream(true)
      //.enable_zstd(true)
      .min_size(1024)
      .brotli_level(9)
      .build(),
);

Route‑level plugin (illustrative):

let mut router = Router::new();
let route = router.route(Method::GET, "/api/data", handler);

// Apply CORS only to this route
let cors = CorsBuilder::new()
    .allow_origin("https://example.com")
    .build();

route.plugin(cors);

GraphQL: HTTP and subscriptions

Extractors/Responders for HTTP; subscription driver for WS.

// POST /graphql
router.route(Method::POST, "/graphql", {
    let schema = schema.clone();
    move |GraphQLRequest(req): GraphQLRequest| {
      let schema = schema.clone();
      async move {
        let resp = schema.execute(req).await;
        GraphQLResponse(resp)
      }
    }
});

  // GET /ws for subscriptions (graphql-transport-ws or graphql-ws)
router.route(Method::GET, "/ws", {
    let schema = schema.clone();
    move |req: TakoRequest| {
      let schema = schema.clone();
      async move { GraphQLSubscription::new(req, schema) }
    }
});

Routing and DX

  • Trailing Slash Redirect (TSR) and custom fallback handlers
  • Handler macro allows multiple extractor arguments; easy ergonomic signatures
  • anyhow::Result implements Responder for simpler error returns

Fallbacks (illustrative):

let mut router = Router::new();
router.route(Method::GET, "/", |_req| async { "Hello" });

// Simple fallback
router.fallback(|_req| async { NOT_FOUND });

// Or with extractors
router.fallback_with_extractors(|Path(id): Path<String>| async move {
  (StatusCode::NOT_FOUND, format!("No route for {id}"))
});

WebSockets

Built‑in WS driver and examples (echo + ticker):

pub async fn ws_echo(req: Request) -> impl Responder {
  TakoWs::new(req, |mut ws| async move {
    let _ = ws.send(Message::Text("Welcome to Tako WS!".into())).await;

    while let Some(Ok(msg)) = ws.next().await {
      match msg {
        Message::Text(txt) => {
          let _ = ws
            .send(Message::Text(Utf8Bytes::from(format!("Echo: {txt}"))))
            .await;
        }
        Message::Binary(bin) => {
          let _ = ws.send(Message::Binary(bin)).await;
        }
        Message::Ping(p) => {
          let _ = ws.send(Message::Pong(p)).await;
        }
        Message::Close(_) => {
          let _ = ws.send(Message::Close(None)).await;
          break;
        }
        _ => {}
      }
    }
  })
}

Routes:

router.route(Method::GET, "/ws/echo", ws_echo);
router.route(Method::GET, "/ws/tick", ws_tick);

Redirect helpers

Convenience functions for common redirect responses.

use tako::{redirect, responder::Responder};

async fn go_home() -> impl Responder {
    redirect::found("/")
}

async fn login_redirect() -> impl Responder {
    // Preserve method (307) or change to GET (303) depending on needs
    redirect::temporary("/login")
}

If you like it drop a ⭐ on Github or just open an issue if something you dont like.

Made by love! 🦀🦀