Routing
Define endpoints that map HTTP methods and paths to handler functions. Express supports GET,
POST, PUT, PATCH, and DELETE out of the box.
This guide walks through building a REST API while showcasing the interactive components available in Starlight. Components are imported from @astrojs/starlight/components and used directly in your content.
Set up your project
Create a new directory and initialize your API project. We will use a simple Node.js setup with Express.
mkdir my-api && cd my-apinpm init -yInstall dependencies
Install Express and a few helpful utilities for building a production-ready API.
bash npm install express cors helmet morgan bash pnpm add express cors helmet morgan bash yarn add express cors helmet morgan Create the entry point
Create an index.js file with the basic server setup:
const express = require("express");const cors = require("cors");const helmet = require("helmet");const morgan = require("morgan");
const app = express();
app.use(cors());app.use(helmet());app.use(morgan("combined"));app.use(express.json());
app.listen(3000, () => { console.log("API running on http://localhost:3000");});Define your first route
Add a health check endpoint so monitoring tools can verify the API is running.
app.get("/health", (req, res) => { res.json({ status: "ok", uptime: process.uptime() });});Test the API
Start the server and confirm everything works:
node index.jscurl http://localhost:3000/healthRouting
Define endpoints that map HTTP methods and paths to handler functions. Express supports GET,
POST, PUT, PATCH, and DELETE out of the box.
Middleware
Functions that run before your route handler. Use them for authentication, logging, input validation, and error handling.
Authentication
Protect your endpoints with API keys, JWT tokens, or OAuth. Always validate credentials in middleware, not in individual route handlers.
Error Handling
Return consistent error responses with appropriate HTTP status codes. A global error handler catches anything your routes miss.
Every endpoint should return a consistent JSON structure. Here is the pattern used throughout this API:
{ "status": "success", "data": { "id": 42, "name": "Example Resource", "created_at": "2026-03-17T10:00:00Z" }}{ "status": "error", "error": { "code": "VALIDATION_FAILED", "message": "The 'email' field must be a valid email address.", "details": [ { "field": "email", "issue": "invalid_format" } ] }}{ "status": "success", "data": [ { "id": 1, "name": "First" }, { "id": 2, "name": "Second" } ], "meta": { "page": 1, "per_page": 20, "total": 87 }}When documenting your API, use badges to communicate the stability of each endpoint:
| Endpoint | Method | Status |
|---|---|---|
/v1/users | GET | Stable |
/v1/users/:id | GET | Stable |
/v1/users | POST | Stable |
/v1/users/:id/avatar | PUT | Beta |
/v1/search | GET | Experimental |
/v1/webhooks | POST | New |
Starlight with MDX supports embedding framework components directly. This counter is a Solid.js component hydrated on the client:
Start from a different value by passing the initial attribute:
This works by importing an Astro wrapper around a Solid.js component with client:visible hydration.