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.
- Overview
- Features
- Changelog
- What's Coming Next
- Installation
- How to Use burger-api
- API Documentation
- Contributing
- License
- FAQs & Resources
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 familiarreq, 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.
-
β‘ 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
.
- Supports dynamic routes via folder names like
-
π οΈ 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)
- OpenAPI Options:
-
π Swagger UI Integration:
Provides a/docs
endpoint serving an interactive Swagger UI that reads from/openapi.json
.
For detailed release notes, please refer to the Changelog file.
- π 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
We're actively enhancing burger-api with powerful new features:
- π₯ 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.
Install burger-api via bun:
bun add burger-api
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.
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
Here's how to implement this structure:
- 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();
};
- 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();
};
- 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(),
}),
};
- 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 });
}
- 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
-
π Static API Route:
Place a file atsrc/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
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',
});
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
- π 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
<!-- pages/products/[id]/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Product Details</title>
</head>
<body>
<h1>Product Details</h1>
<!-- Content here -->
</body>
</html>
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);
}
-
π OpenAPI JSON:
Accesshttp://localhost:4000/openapi.json
to view the auto-generated OpenAPI specification. -
π Swagger UI:
Accesshttp://localhost:4000/docs
to view interactive API documentation via Swagger UI.
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.
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.
-
π 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 undersrc/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 anopenapi
object in your route files.
burger-api aims to revolutionize your API development experience with simplicity, speed, and cutting-edge features. Happy coding! π