You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

astro-routify

Package Overview
Dependencies
Maintainers
0
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

astro-routify

A high-performance API router for Astro using a Trie-based matcher.

1.2.1
latest
Source
npmnpm
Version published
Maintainers
0
Created
Source

astro-routify

A high-performance API router for Astro built on a Trie matcher.
Define API routes using clean, flat structures — no folders or boilerplate logic.

npm license downloads feedback-welcome

Installing

npm install astro-routify

⚡️ Quickstart

// src/pages/api/index.ts
import {
    defineRoute,
    defineRouter,
    defineGroup,
    HttpMethod,
    ok,
} from 'astro-routify';

const userGroup = defineGroup('/users', (group) => {
    group.addGet('/:id', ({params}) => ok({id: params.id}));
});

export const GET = defineRouter([
    defineRoute(HttpMethod.GET, '/ping', () => ok('pong')),
    ...userGroup.getRoutes(),
]);

Or to handle everything in a single place:

import {RouterBuilder, ok} from 'astro-routify';

const builder = new RouterBuilder();

builder
    .addGet('/ping', () => ok('pong'))
    .addPost('/submit', async ({request}) => {
        const body = await request.json();
        return ok({received: body});
    });

export const ALL = builder.build(); // catch-all

💡 Full Example

You can find an implementation example in the astro-routify-example repository. It showcases a minimal Astro app with API endpoints configured under:

/src/pages/api/[...path].ts

This setup demonstrates how to route requests dynamically using astro-routify, while still leveraging Astro's native endpoint system.

🚀 Features

  • ⚡ Fully compatible with Astro’s native APIContext — no extra setup needed.
  • 🧩 Use middleware, access cookies, headers, and request bodies exactly as you would in a normal Astro endpoint.
  • ✅ Flat-file, code-based routing (no folders required)
  • ✅ Dynamic segments (:id)
  • ✅ ALL-mode for monolithic routing (RouterBuilder)
  • ✅ Built-in response helpers (ok, created, etc.)
  • ✅ Trie-based matcher for fast route lookup
  • ✅ Fully typed — no magic strings
  • 🔁 Streaming support
    • stream() — raw streaming with backpressure support (e.g. SSE, logs, custom protocols)
    • streamJsonND() — newline-delimited JSON streaming (NDJSON)
    • streamJsonArray() — server-side streamed JSON arrays

🔄 See CHANGELOG.md for recent updates and improvements.

🧠 Core Concepts

defineRoute()

Declare a single route:

defineRoute(HttpMethod.GET, "/users/:id", ({params}) => {
    return ok({userId: params.id});
});

defineRouter()

Group multiple routes under one HTTP method handler:

export const GET = defineRouter([
    defineRoute(HttpMethod.GET, "/health", () => ok("ok"))
]);

🧠 defineRouter() supports all HTTP methods — but Astro only executes the method you export (GET, POST, etc.)

RouterBuilder (Catch-All & Fluent Builder)

Use RouterBuilder when you want to build routes dynamically, catch all HTTP methods via ALL, or organize routes more fluently with helpers.

const builder = new RouterBuilder();

builder
    .addGet("/ping", () => ok("pong"))
    .addPost("/submit", async ({request}) => {
        const body = await request.json();
        return ok({received: body});
    });

export const ALL = builder.build();

You can also group routes:

const users = defineGroup("/users")
    .addGet("/:id", ({params}) => ok({id: params.id}));

builder.addGroup(users);

🔁 While .register() is still available, it's deprecated in favor of .addGroup() and .addRoute() for better structure and reusability.

🔁 Response Helpers

Avoid boilerplate new Response(JSON.stringify(...)):

import {fileResponse} from 'astro-routify';

ok(data);                   // 200 OK
created(data);              // 201 Created
noContent();                // 204
notFound("Missing");        // 404
internalError(err);         // 500

📄 File downloads

fileResponse(content, "application/pdf", "report.pdf"); // sets Content-Type and Content-Disposition

🔄 Streaming responses

Raw stream (e.g., Server-Sent Events)

stream('/clock', async ({response}) => {
    const timer = setInterval(() => {
        response.write(new Date().toISOString());
    }, 1000);

    setTimeout(() => {
        clearInterval(timer);
        response.close();
    }, 5000);
});

JSON NDStream (newline-delimited)


streamJsonND('/updates', async ({response}) => {
    response.send({step: 1});
    await delay(500);
    response.send({step: 2});
    response.close();
});

JSON Array stream


streamJsonArray('/items', async ({response}) => {
    for (let i = 0; i < 3; i++) {
        response.send({id: i});
    }
    response.close();
});

🔍 Param Matching

Any route param like :id is extracted into ctx.params:

const builder = new RouterBuilder();

builder.addGet("/users/:id", ({params}) => ok({userId: params.id}));


//OR

defineRoute(HttpMethod.GET, "/items/:id", ({params}) => {
    return ok({itemId: params.id});
});

🤯 Why Use astro-routify?

❌ Without it

// src/pages/api/[...slug].ts
export const GET = async ({request}) => {
    const url = new URL(request.url);
    const path = url.pathname;

    if (path.startsWith('/api/users/')) {
        // Try to extract ID
        const id = path.split('/').pop();
        return new Response(JSON.stringify({id}), {
            status: 200,
            headers: {'Content-Type': 'application/json'},
        });
    }

    if (path === '/api/users') {
        return new Response(JSON.stringify([{id: 1}, {id: 2}]), {
            status: 200,
            headers: {'Content-Type': 'application/json'},
        });
    }

    if (path === '/api/ping') {
        return new Response(JSON.stringify({pong: true}), {
            status: 200,
            headers: {'Content-Type': 'application/json'}
        });
    }

    return new Response('Not Found', {status: 404});
};

📁 And then there's folder hell...

src/
├─ pages/
│  ├─ api/
│  │  ├─ users/
│  │  │  ├─ index.ts       // GET all users
│  │  │  ├─ [id]/
│  │  │  │  ├─ index.ts    // GET / POST / DELETE for a user
│  │  ├─ ping.ts

✅ With astro-routify

// src/pages/api/[...slug].ts

const builder = new RouterBuilder();
builder.addGet("/ping", () => ok({pong: true}));
builder.addGet("/users/:id", ({params}) => ok({userId: params.id}));

// OR

export const ALL = defineRouter([
    defineRoute(HttpMethod.GET, "/ping", () => ok({pong: true})),
    defineRoute(HttpMethod.GET, "/users/:id", ({params}) => ok({id: params.id}))
]);

📈 Performance

astro-routify uses a Trie structure for fast route and method matching.
It’s optimized for real-world route hierarchies, and avoids nested if chains.

🧪 Benchmarks

Realistic and synthetic benchmarks using vitest bench.

🖥 Benchmark Machine

Tests ran on a mid-range development setup:

  • CPU: Intel Core i5-7600K @ 3.80GHz (4 cores)
  • RAM: 16 GB DDR4
  • GPU: NVIDIA GeForce GTX 1080 (8 GB)
  • OS: Windows 10 Pro 64-bit
  • Node.js: v20.x
  • Benchmark Tool: Vitest Bench

Results may vary slightly on different hardware.

🔬 Realistic route shapes (5000 registered routes):

✓ RouteTrie performance - realistic route shapes

 · Static route lookup (5000)                         1,819,681 req/sec
 · Param route: /users/:userId                        1,708,264 req/sec
 · Nested param route: /users/:id/orders/:oid         1,326,324 req/sec
 · Blog route: /blog/:year/:month/:slug               1,220,882 req/sec
 · Nonexistent path                                   1,621,934 req/sec

📈 Route scaling test:

✓ RouteTrie performance

 · Lookup in SMALL (100 routes)                       1,948,385 req/sec
 · Lookup in MEDIUM (1000 routes)                     1,877,248 req/sec
 · Lookup in LARGE (10000 routes)                     1,908,279 req/sec
 · Lookup non-existent route in LARGE                 1,962,051 req/sec

⚡ Performance stays consistently fast even with 10k+ routes

🛠 Designed to Scale

While focused on simplicity and speed today, astro-routify is designed to evolve — enabling more advanced routing patterns in the future.

📜 License

MIT — © 2025 Alex Mora

☕ Support

If this project helps you, consider buying me a coffee. Every drop keeps the code flowing!

Keywords

astro

FAQs

Package last updated on 02 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.