Skip to content

burger-api is a modern, open source API framework built on Bun.js. It combines the simplicity of file-based routing with powerful features like built-in middleware, Zod-based schema validation, and automatic OpenAPI generation.

License

Notifications You must be signed in to change notification settings

Isfhan/burger-api

Repository files navigation

BurgerAPI logo

Under Development License Bun

burger-api is a modern, open source API framework built on Bun.js. It combines the simplicity of file-based routing with powerful features like built-in middleware, Zod-based schema validation, and automatic OpenAPI generation. Designed for high performance and ease-of-use, burger-api leverages Bun's native modules to deliver blazing-fast API responses while keeping your codebase clean and maintainable.

This project is under active development and should not be used in production yet.

πŸ“š Table of Contents

πŸš€ Overview

burger-api is built to offer a robust developer experience through:

  • ⚑ Bun-Native Performance:
    Leverages Bun's high-performance HTTP server.

  • πŸ“ File-Based Routing:
    Automatically registers API routes from your file structure using a clear naming convention.

  • πŸ”„ Middleware Architecture:
    Supports both global and route-specific middleware with a familiar req, res, next pattern.

  • βœ… Type-Safe Validation:
    Utilizes Zod for request validation, ensuring full type safety and automatic error reporting.

  • πŸ“š Automatic OpenAPI Generation:
    Generates a complete OpenAPI 3.0 specification (with support for tags, summaries, descriptions, operationId, deprecated status, externalDocs, and more) directly from your routes and Zod schemas.

  • πŸ” Swagger UI Integration:
    Provides an out-of-the-box Swagger UI endpoint for interactive API documentation.

✨ Features

Core Features

  • ⚑ Bun-Native HTTP Server:
    Built on Bun's native APIs for exceptional performance.

  • πŸ“ File-Based Routing Engine:
    Automatically scans directories to register routes.

    • Supports dynamic routes via folder names like [id] for /api/product/:id.
  • πŸ› οΈ Request & Response Enhancements:

    • BurgerRequest extends the native Request to include query, params, and validated data.
    • BurgerResponse provides methods to set headers, status, and build responses (JSON, text, HTML, redirects, files).
  • πŸ”„ Middleware System:

    • Global Middleware: Runs on every request.
    • Route-Specific Middleware: Defined in individual route files.
    • Validation Middleware: Automatically validates request data using Zod schemas exported from routes.
  • βœ… Zod-Based Schema Validation:
    Automatically validates request params, query, and body using Zod.

    • Supports preprocessing (e.g., converting URL parameters from string to number).
  • πŸ“š Automatic OpenAPI Specification Generation:
    Generates an OpenAPI 3.0 document using route metadata and Zod schemas.

    • OpenAPI Options:
      • Global metadata (title, description, version)
      • Per-route metadata (summary, description, tags, operationId, deprecated, externalDocs)
      • Auto-generated parameters and requestBody schemas (using zod-to-json-schema for detailed inline JSON schema definitions)
  • πŸ” Swagger UI Integration:
    Provides a /docs endpoint serving an interactive Swagger UI that reads from /openapi.json.

πŸ“£ Changelog

For detailed release notes, please refer to the Changelog file.

Version 0.1.3 (March 15, 2024)

  • πŸ”„ Bug Fixes and Improvements:
    • Enhanced page routing and server response handling
    • Improved import paths configuration in tsconfig.json
    • Updated request/response handling
    • Enhanced server initialization process
    • Improved native types handling
    • Updated server response functionality

🎯 What's Coming Next?

We're actively enhancing burger-api with powerful new features:

🎨 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

Stay tuned for updates as we continue to build and improve burger-api! We're committed to making it the best API framework for Bun.js.

πŸ“¦ Installation

Install burger-api via bun:

bun add burger-api

πŸš€ How to Use burger-api

Basic Usage Example

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}`);
});

The debug option enables:

  • πŸ” Interactive stack trace page at when errors occur
    • Shows detailed error information
    • Displays the full stack trace
    • Highlights the exact line where the error occurred
    • Provides request context and environment details

This is particularly useful during development to understand how your API is working and troubleshoot issues.

Recommended Project Structure

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

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

Example Implementation

Here's how to implement this structure:

  1. Global Middleware (src/middleware/global/logger.ts):
import type { BurgerRequest, BurgerResponse, BurgerNext } from 'burger-api';

export const logger = async (
    req: BurgerRequest,
    res: BurgerResponse,
    next: BurgerNext
) => {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    return next();
};
  1. Route-Specific Middleware (src/middleware/routes/products.ts):
import type { BurgerRequest, BurgerResponse, BurgerNext } from 'burger-api';

export const validateProductAccess = async (
    req: BurgerRequest,
    res: BurgerResponse,
    next: BurgerNext
) => {
    // Your middleware logic here
    return next();
};
  1. Schemas (src/schemas/product.ts):
import { z } from 'zod';

export const productSchema = {
    create: z.object({
        name: z.string().min(1),
        price: z.number().positive(),
        description: z.string().optional(),
    }),
    update: z.object({
        name: z.string().min(1).optional(),
        price: z.number().positive().optional(),
        description: z.string().optional(),
    }),
};
  1. Route File (src/api/products/route.ts):
import type { BurgerRequest, BurgerResponse } from 'burger-api';
import { validateProductAccess } from '../../middleware/routes/products';
import { productSchema } from '../../schemas/product';

export const middleware = [validateProductAccess];
export const schema = {
    post: {
        body: productSchema.create,
    },
    put: {
        body: productSchema.update,
    },
};

export async function GET(req: BurgerRequest, res: BurgerResponse) {
    return res.json({ message: 'List of products' });
}

export async function POST(req: BurgerRequest, res: BurgerResponse) {
    const body = req.validated?.body;
    return res.json({ message: 'Product created', data: body });
}
  1. Main Application (src/index.ts):
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',
});

burger.serve(4000, (port) => {
    console.log(`Server is running on port ${port}`);
});

This structure provides several benefits:

  • 🎯 Clear separation of concerns
  • πŸ“ Easy to find and maintain code
  • πŸ”„ Reusable components
  • 🧹 Clean and organized codebase
  • πŸ“š Better scalability

File-Based Routing Examples

  • πŸ“„ Static API Route:
    Place a file at src/api/route.ts to handle the root API endpoint (e.g., /api).

  • πŸ”„ Dynamic API Route:
    For routes with dynamic segments, create folders with square brackets. For example:

    src/api/product/
    β”œβ”€β”€ route.ts         // Handles /api/product
    └── [id]/
        └── route.ts     // Handles /api/product/:id
    

Page Directory Structure

burger-api supports serving static pages alongside your API routes. Here's how to use the pageDir feature:

const burger = new Burger({
    title: 'My Custom API',
    description: 'Custom API with auto-generated docs and validation',
    apiDir: 'api',
    pageDir: 'pages', // Enable page serving from the pages directory
    globalMiddleware: [globalLogger],
    version: '1.0.0',
});

Page Directory Structure Example:

my-api/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ pages/                  # Pages directory
β”‚   β”‚   β”œβ”€β”€ index.html         # Home page (/)
β”‚   β”‚   β”œβ”€β”€ about.html         # About page (/about)
β”‚   β”‚   └── products/
β”‚   β”‚       β”œβ”€β”€ index.html     # Products list (/products)
β”‚   β”‚       └── [id]/          # Dynamic product pages
β”‚   β”‚           └── index.html # Single product (/products/123)
β”‚   └── api/                   # Your API routes

Page Routing Features:

  • πŸ“„ Index Pages: Files named index.html serve as directory index pages
  • πŸ”„ Clean URLs:
    • /pages/about.html β†’ /about
  • πŸ“ Dynamic Routes: Use [param] syntax in folder names
    • /pages/products/[id]/index.html β†’ /products/:id
  • 🎯 Route Grouping: Use (group) syntax for logical grouping
    • /pages/(auth)/login.html β†’ /login
    • /pages/(auth)/register.html β†’ /register

Example Page Structure:

<!-- pages/products/[id]/index.html -->
<!DOCTYPE html>
<html>
    <head>
        <title>Product Details</title>
    </head>
    <body>
        <h1>Product Details</h1>
        <!-- Content here -->
    </body>
</html>

Route File Example

Below is an example route file demonstrating schema validation, route-specific middleware, and OpenAPI metadata.

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

import { z } from 'zod';
import type { BurgerRequest, BurgerResponse, BurgerNext } 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',
    },
};

// 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(),
        }),
    },
    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: BurgerNext) => {
        console.log('[Product Middleware] Executing product route middleware');
        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());
    return res.json({
        id: validatedParams.id,
        query,
        name: '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());
    return res.json(body);
}

API Documentation Endpoints

  • πŸ“š OpenAPI JSON:
    Access http://localhost:4000/openapi.json to view the auto-generated OpenAPI specification.

  • πŸ” Swagger UI:
    Access http://localhost:4000/docs to view interactive API documentation via Swagger UI.

🀝 Contributing

We welcome contributions from the community! If you have suggestions or improvements, please open an issue or submit a pull request. Let's build something amazing together.

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

The MIT License is a permissive license that is short and to the point. It lets people do anything they want with your code as long as they provide attribution back to you and don't hold you liable.

❓ FAQs & Additional Resources

  • πŸ”„ 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.

  • πŸ“ How does file-based routing work?
    Place your route files under src/api/ or just /api using folder and file naming conventions (e.g., [id] for dynamic routes).

  • βœ… 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.

  • πŸ“š 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.

burger-api aims to revolutionize your API development experience with simplicity, speed, and cutting-edge features. Happy coding! πŸš€

About

burger-api is a modern, open source API framework built on Bun.js. It combines the simplicity of file-based routing with powerful features like built-in middleware, Zod-based schema validation, and automatic OpenAPI generation.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •