BurgerAPIBurgerAPI

BurgerAPIBurgerAPI

A modern, open source API framework built on Bun.js with file-based routing, middleware support, Zod validation, and automatic OpenAPI generation.

Under DevelopmentMIT LicenseBun 1.2.4+

šŸš€ Features

Bun-Native Performance

Utilizes Bun's high-performance HTTP server to provide rapid API responses also use others Bun's native APIs for outstanding speed and efficiency.

File-Based Routing

Automatically registers APIs and static pages routes from your file structure using a clear naming convention. Supports dynamic routes via folder names like [id] for /api/product/:id.

Middleware Architecture

Supports both global and route-specific middleware with a familiar req, res, next pattern. Chain multiple middleware functions to process requests before they reach your route handlers.

Type-Safe Validation

Utilizes Zod for request validation, ensuring full type safety and automatic error reporting. Validates request params, query, and body with support for preprocessing (e.g., converting URL parameters from string to number).

Automatic OpenAPI Generation

Generates a complete OpenAPI 3.0 specification directly from your routes and Zod schemas. Includes support for tags, summaries, descriptions, operationId, deprecated status, and externalDocs for comprehensive API documentation.

Swagger UI Integration

Provides an out-of-the-box Swagger UI endpoint for interactive API documentation. Access your API documentation at /docs with a fully interactive interface for testing endpoints directly from the browser.

šŸŽÆ What's Coming Next?

We're enhancing burger-api to make it even more powerful! While our core focus remains on building fast, type-safe APIs, we're adding the ability to serve simple pages when needed:

šŸŽØ Page Serving Enhancements (In Development)

  • šŸ”„ TSX Support: Adding React/TSX rendering capabilities
  • šŸ” Global Middleware: Applies to all routes for tasks like logging and authentication
  • šŸ” Page-Specific Middleware: Defined in individual route files for tailored processing.
  • šŸ› ļø Advanced Middleware: More built-in middleware for common use cases: CORS handling, Rate limiting, Request logging, Security headers
  • šŸŽÆ Performance Optimizations: Further leveraging Bun's capabilities for faster page serving

šŸ“¦ Installation

Install burger-api via bun:

bash
bun add burger-api

Requirements

  • Bun 1.2.4 or higher
  • TypeScript 5.0 or higher (recommended for type safety)

šŸš€ Basic Usage Example

Create a new Burger instance and start your server:

typescript
import { Burger } from "burger-api";

// Global middleware example: a simple logger.
const globalLogger = async (req, res, next) => {
  console.log(`[Global Logger] ${req.method} ${req.url}`);
  return next();
};

const burger = new Burger({
  title: "My Custom API",
  description: "Custom API with auto-generated docs and validation",
  apiDir: "api",
  globalMiddleware: [globalLogger],
  version: "1.0.0",
  debug: true, // Enable debug mode for detailed logging and stack trace page
});

// Start the server on port 4000 with a callback
burger.serve(4000, (port) => {
  console.log(`Server is running on port ${port}`);
});

Configuration Options

  • title?:The title of your API (used in OpenAPI docs)
  • description?:A description of your API (used in OpenAPI docs)
  • apiDir:The directory where your API routes are located
  • pageDir?:The directory where your static pages are located
  • globalMiddleware:An array of middleware functions to apply to all routes
  • version?:The version of your API (used in OpenAPI docs)
  • debug?:Enable debug mode for detailed logging and interactive stack trace page

Debug Mode Features

When debug: true is set, you get:

  • Interactive stack trace page when errors occur
  • Detailed error information with full stack traces
  • Highlighted code showing exactly where errors occurred
  • Request context and environment details for easier debugging

Recommended Project Structure

Here's a recommended project structure that helps keep your code organized and maintainable:

text
my-api/
ā”œā”€ā”€ src/
ā”‚   ā”œā”€ā”€ api/                    # API routes
ā”‚   ā”‚   ā”œā”€ā”€ products/
ā”‚   ā”‚   ā”‚   ā”œā”€ā”€ route.ts       # Product routes
ā”‚   ā”‚   ā”‚   ā””ā”€ā”€ [id]/
ā”‚   ā”‚   ā”‚       ā””ā”€ā”€ route.ts   # Product detail routes
ā”‚   ā”‚   ā””ā”€ā”€ users/
ā”‚   ā”‚       ā””ā”€ā”€ route.ts       # User routes
ā”‚   ā”œā”€ā”€ middleware/            # Middleware
ā”‚   ā”‚   ā”œā”€ā”€ global/           # Global middleware
ā”‚   ā”‚   ā”‚   ā”œā”€ā”€ logger.ts
ā”‚   ā”‚   ā”‚   ā””ā”€ā”€ auth.ts
ā”‚   ā”‚   ā””ā”€ā”€ routes/           # Route-specific middleware
ā”‚   ā”‚       ā”œā”€ā”€ products.ts
ā”‚   ā”‚       ā””ā”€ā”€ users.ts
ā”‚   ā”œā”€ā”€ schemas/              # Zod schemas
ā”‚   ā”‚   ā”œā”€ā”€ product.ts
ā”‚   ā”‚   ā””ā”€ā”€ user.ts
ā”‚   ā”œā”€ā”€ utils/               # Utility functions
ā”‚   ā”‚   ā”œā”€ā”€ errors.ts
ā”‚   ā”‚   ā””ā”€ā”€ helpers.ts
ā”‚   ā””ā”€ā”€ index.ts             # Main application file
ā”œā”€ā”€ package.json
ā””ā”€ā”€ tsconfig.json

Structure Benefits

šŸŽÆ Clear separation of concerns

Each part of your application has its own dedicated location

šŸ“ Easy to find and maintain code

Logical organization makes navigation intuitive

šŸ”„ Reusable components

Middleware and schemas can be shared across routes

šŸ“š Better scalability

Structure grows naturally as your API expands

šŸ“ Examples

Main Application (src/index.ts)

The main application file creates and configures the Burger instance and starts the server.

typescript
import { Burger } from "burger-api";
import { logger } from "./middleware/global/logger";

const burger = new Burger({
  title: "Product API",
  description: "API for managing products",
  apiDir: "api",
  globalMiddleware: [logger],
  version: "1.0.0",
  debug: process.env.NODE_ENV !== "production", // Enable debug mode in development
});

const PORT = process.env.PORT ? parseInt(process.env.PORT) : 4000;

burger.serve(PORT, (port) => {
  console.log(`Server is running on port ${port}`);
  console.log(`API Documentation: http://localhost:${port}/docs`);
  console.log(`OpenAPI Spec: http://localhost:${port}/openapi.json`);
});

Advanced Route Example

This example demonstrates a more complex route with dynamic parameters, query validation, and OpenAPI metadata.

typescript
// examples/demo/api/product/[id]/route.ts

import { z } from "zod";
import type { BurgerRequest, BurgerResponse } from "burger-api";

// OpenAPI metadata for this route
export const openapi = {
  get: {
    summary: "Get Product Details",
    description: "Retrieves product details by product ID.",
    tags: ["Product"],
    operationId: "getProductDetails",
  },
  put: {
    summary: "Update Product",
    description: "Updates an existing product by ID.",
    tags: ["Product"],
    operationId: "updateProduct",
  },
  delete: {
    summary: "Delete Product",
    description: "Deletes a product by ID.",
    tags: ["Product"],
    operationId: "deleteProduct",
  }
};

// Validation Schemas for GET and POST requests
export const schema = {
  get: {
    params: z.object({
      id: z.preprocess(
        (val) => (typeof val === "string" ? parseInt(val, 10) : val),
        z.number().min(1, "ID is required")
      ),
    }),
    query: z.object({
      search: z.string().optional(),
      includeDeleted: z.preprocess(
        (val) => val === "true",
        z.boolean().optional()
      ),
    }),
  },
  post: {
    body: z.object({
      name: z.string().min(1, "Name is required"),
      price: z.number().positive("Price must be positive"),
    }),
  },
};

// Route-specific middleware
export const middleware = [
  async (
    req: BurgerRequest,
    res: BurgerResponse,
    next: () => Promise<Response>
  ) => {
    console.log("[Product Middleware] Executing product route middleware");
    // You could add authentication or logging here
    return next();
  },
];

// GET handler: returns product details
export async function GET(
  req: BurgerRequest,
  res: BurgerResponse,
  params: { id: number }
) {
  console.log("[GET] Product route invoked");
  const validatedParams = (req.validated?.params as { id: number }) || params;
  const query = req.validated?.query || Object.fromEntries(req.query.entries());
  
  // In a real app, you would fetch the product from a database
  return res.json({
    id: validatedParams.id,
    query,
    name: "Sample Product",
    price: 99.99,
    description: "This is a sample product",
  });
}

// POST handler: creates a new product
export async function POST(req: BurgerRequest, res: BurgerResponse) {
  console.log("[POST] Product route invoked");
  const body = req.validated?.body || (await req.json());
  
  // In a real app, you would save the product to a database
  return res.json(body);
}

// PUT handler: updates a product
export async function PUT(
  req: BurgerRequest,
  res: BurgerResponse,
  params: { id: number }
) {
  const id = params.id;
  const body = req.validated?.body || (await req.json());
  
  // In a real app, you would update the product in a database
  return res.json({
    id,
    ...body,
    updated: true,
  });
}

// DELETE handler: deletes a product
export async function DELETE(
  req: BurgerRequest,
  res: BurgerResponse,
  params: { id: number }
) {
  const id = params.id;
  
  // In a real app, you would delete the product from a database
  return res.json({
    id,
    deleted: true,
  });
}

šŸ“š API Documentation Endpoints

OpenAPI JSON

Access the auto-generated OpenAPI specification at:

http://localhost:4000/openapi.json

This endpoint provides a complete OpenAPI 3.0 specification of your API, including all routes, parameters, request bodies, and responses. You can use this JSON file with any OpenAPI-compatible tool.

Swagger UI

Access interactive API documentation via Swagger UI at:

http://localhost:4000/docs

The Swagger UI provides an interactive interface for exploring and testing your API. You can see all available endpoints, try them out with different parameters, and view the responses directly in your browser.

ā“ FAQs

How do I add custom middleware?

You can pass an array of global middleware in the Burger options or export route-specific middleware in your route files.

typescript
// Global middleware (in your main file)
const burger = new Burger({
  // ...other options
  globalMiddleware: [logger, authMiddleware, corsMiddleware],
});

// Route-specific middleware (in your route file)
export const middleware = [validateProductAccess, rateLimit];

How does file-based routing work?

Place your route files under src/api/ or just /api using folder and file naming conventions.

Static Routes

api/users/route.ts ā†’ /api/users

Dynamic Routes

api/users/[id]/route.ts ā†’ /api/users/:id

Grouped Routes

api/(public)/users/route.ts ā†’ /api/users

How is validation handled?

burger-api uses Zod for schema validation. Define your schemas in your route files and they are automatically used to validate incoming requests.

typescript
// In your route file
export const schema = {
  get: {
    params: z.object({
      id: z.preprocess(
        (val) => (typeof val === "string" ? parseInt(val, 10) : val),
        z.number().min(1, "ID is required")
      ),
    }),
    query: z.object({
      search: z.string().optional(),
    }),
  },
  post: {
    body: z.object({
      name: z.string().min(1, "Name is required"),
      price: z.number().positive("Price must be positive"),
    }),
  },
};

When a request is received, burger-api automatically validates it against the appropriate schema and makes the validated data available in req.validated.

How can I customize the OpenAPI documentation?

Override the default auto-generated summaries, descriptions, tags, and operationIds by exporting an openapi object in your route files.

typescript
// In your route file
export const openapi = {
  get: {
    summary: "Get Product Details",
    description: "Retrieves product details by product ID.",
    tags: ["Product"],
    operationId: "getProductDetails",
    deprecated: false,
    externalDocs: {
      description: "Product API Documentation",
      url: "https://example.com/docs/products",
    },
  },
};