What is @aura-stack/router
Welcome to @aura-stack/router package. It is a modern, TypeScript-first router and endpoint definition library for TypeScript backends that provides supported for Next.js, Nuxt, Sveltekit and more.
Build fully-typed APIs with declarative endpoints, automatic parameter inference, and first-class middleware support — all returning native Response objects for seamless compatibility with the Fetch API and modern API to be supported by the major of professional TypeScript applications.
All of the package is built-in in TypeScript providing a strong type-safe and type-inference for a better experience coding.
Getting Started
This guide will help you install and set up @aura-stack/router in your TypeScript project and understanding the fundamental concepts of @aura-stack/router will help you build type-safe APIs efficiently.
Installation
Install the package and its peer dependency:
npm install @aura-stack/router zod
zodis a peer dependency required for schema validation features configured increateEndpointdeclarative function.
Endpoints
Endpoints are the building blocks of your API. Each endpoint represents a single route with a specific HTTP method.
Creating Endpoints
Use createEndpoint to define an endpoint:
import { createEndpoint } from "@aura-stack/router"
const getUser = createEndpoint(
"GET", // HTTP method
"/users/:userId",
async (request, ctx) => {
const { userId } = ctx.params
return Response.json({ id: userId, name: "John" })
}
)Supported HTTP Methods
Currently is supoprted five HTTP methods, based on the recommended and suggested HTTP methods to be used in an clean API Restful.
GET- Retrieve resourcesPOST- Create resourcesPUT- Replace resourcesPATCH- Update resourcesDELETE- Delete resources
Route Patterns
Routes use a simple pattern syntax for dynamic segments:
Static Routes
const endpoint = createEndpoint("GET", "/about", handler)Dynamic Parameters
The dynamic parameters are automatically extracted from the route definition with the :paramName and are passed to the context of the handlers to be acceded ctx.params
import { createEndpoint } from "@aura-stack/router"
/*
Single parameter
*/
const getUser = createEndpoint("GET", "/users/:userId", async (_, ctx) => {
return Response.json({ message: "" })
})
/*
Multiple parameters
*/
const getComment = createEndpoint("GET", "/posts/:postId/comments/:commentId", async (_, ctx) => {
return Response.json({})
})Request Context
Every handler receives a RequestContext object with parsed request data:
interface RequestContext<RouteParams, Config> {
/* Route parameters */
params: RouteParams
/* Query parameters */
searchParams: URLSearchParams | ParsedObject
/* Request body */
body: unknown | ParsedObject
/* HTTP headers */
headers: Headers
}Accessing Context
const handler = async (request, ctx) => {
/* Route parameters */
const { userId } = ctx.params
/* Query parameters */
const page = ctx.searchParams.get("page")
/* Request body */
const data = ctx.body
/* Headers */
const auth = ctx.headers.get("authorization")
return Response.json({ userId, page, data })
}Routers
Routers group endpoints and provide type-safe HTTP handlers.
Creating Routers
import { createRouter } from "@aura-stack/router"
const router = createRouter([endpoint1, endpoint2, endpoint3])Type-Safe Method Extraction
Only methods used in your endpoints are available:
import { createEndpoint, createRouter } from "@aura-stack/router"
const getUser = createEndpoint("GET", "/users/:id", async () => {
return Response.json({})
})
const createUser = createEndpoint("POST", "/users", async () => {
return Response.json({})
})
const { GET, POST } = createRouter([getUser, createUser])
// @errors: 2339
const { DELETE } = createRouter([getUser, createUser])Router Configuration
Base Path
Prefix all routes with a base path:
const router = createRouter([...endpoints], {
basePath: "/api/v1",
})
/*
Routes become:
- /api/v1/users
- /api/v1/posts
*/Global Middlewares
Apply middlewares to all endpoints:
const router = createRouter([...endpoints], {
middlewares: [loggingMiddleware, authMiddleware],
})Response Handling
All handlers must return a standard Response object:
JSON Responses
return Response.json({ data: "value" })
return Response.json({ error: "Not found" }, { status: 404 })Text Responses
return new Response("Hello, World!")
return new Response("Created", { status: 201 })Redirects
return Response.redirect("https://example.com")
return Response.redirect("/login", 302)Custom Headers
return Response.json(
{ data: "value" },
{
headers: {
"Cache-Control": "max-age=3600",
"X-Custom-Header": "value",
},
}
)Type Inference
The library provides automatic type inference throughout:
Route Parameters
import { createEndpoint } from "@aura-stack/router"
const endpoint = createEndpoint("GET", "/users/:userId/posts/:postId", async (request, ctx) => {
const { userId, postId } = ctx.params
return Response.json({})
})Schema-Based Typing
When using Zod schemas, body and searchParams are fully typed:
import { z } from "zod"
import { createEndpoint, createEndpointConfig } from "@aura-stack/router"
const config = createEndpointConfig({
schemas: {
body: z.object({
email: z.string().email(),
age: z.number(),
}),
searchParams: z.object({
page: z.string().optional(),
}),
},
})
const endpoint = createEndpoint(
"POST",
"/users",
async (request, ctx) => {
const { email, age } = ctx.body
return Response.json({})
},
config
)Next Steps
- Understand Middlewares