A high-performance, minimalist HTTP framework for Bun, inspired by 0http. Built specifically to leverage Bun's native performance capabilities with a developer-friendly API.
Landing page: 0http-bun.21no.de
v1.3.0 includes a comprehensive security hardening release. See the Changelog and Migration Guide sections below.
0http-bun combines the simplicity of Express with the raw performance of Bun's runtime, delivering a framework that's both blazingly fast and secure by design. Perfect for everything from quick prototypes to production-grade APIs.
- Bun-Native Optimization: Built specifically for Bun's runtime with zero overhead
- Lightning-Fast Routing: Based on the proven
trouterlibrary with intelligent caching - Memory Efficient: Smart object reuse and minimal allocations
- Optimized Parsing: Uses
fast-querystringfor lightning-quick query string handling
- TypeScript First: Full type safety with comprehensive definitions
- Intuitive API: Clean, expressive syntax that's easy to learn
- Flexible Middleware: Powerful async/await middleware system
- Web Standards: Built on standard Request/Response APIs
- Production-Ready Security: Built-in protection against common vulnerabilities
- Input Validation: Comprehensive sanitization and size limits
- Attack Prevention: Prototype pollution, ReDoS, and DoS protection
- Secure Defaults: Safe error handling and CORS configuration
- 🚀 Bun-Native Performance: Optimized for Bun's runtime with minimal overhead
- 🔧 TypeScript First: Full TypeScript support with comprehensive type definitions
- 🎯 Minimalist API: Clean, intuitive API that's easy to learn and use
- 🔄 Middleware Support: Flexible middleware system with async/await support
- 📦 Tiny Footprint: Lightweight framework focused on performance
- 🛡️ Web Standards: Built on standard Web APIs (Request/Response)
bun add 0http-bunimport http from '0http-bun'
const {router} = http()
router.get('/', () => {
return new Response('Hello World!')
})
router.get('/:id', (req) => {
return Response.json({id: req.params.id})
})
// Start the server
Bun.serve({
port: 3000,
fetch: router.fetch,
})Bun's standard Request object does not expose the client IP address. To enable the default rate limiter key generator (and any middleware that reads req.ip), use server.requestIP() in the Bun.serve fetch handler:
import http from '0http-bun'
import {createRateLimit} from '0http-bun/lib/middleware'
const {router} = http()
router.use(createRateLimit({windowMs: 15 * 60 * 1000, max: 100}))
router.get('/', () => new Response('Hello World!'))
// Populate req.ip from Bun's server.requestIP before passing to the router
Bun.serve({
port: 3000,
fetch(req, server) {
req.ip = server.requestIP(req)?.address
return router.fetch(req)
},
})Why is this needed? The Fetch API
Requesttype does not include connection-level properties likeip. Bun provides client IP viaserver.requestIP(req)in the fetch handler's second argument. Settingreq.ipbefore callingrouter.fetchensures the rate limiter (and other middleware) can identify clients correctly. Without this, the default key generator falls back to unique per-request keys, which effectively disables rate limiting.
import http, {ZeroRequest, StepFunction} from '0http-bun'
const {router} = http({
port: 3000,
errorHandler: (err: Error) => {
console.error('Server error:', err)
return new Response('Internal Server Error', {status: 500})
},
})
// Typed middleware
router.use((req: ZeroRequest, next: StepFunction) => {
req.ctx = {
startTime: Date.now(),
engine: 'bun',
}
return next()
})
// Typed route handlers
router.get('/:id', async (req: ZeroRequest) => {
return Response.json({
id: req.params.id,
context: req.ctx,
})
})
router.post('/users', async (req: ZeroRequest) => {
const body = await req.json()
return Response.json({created: true, data: body}, {status: 201})
})interface IRouterConfig {
defaultRoute?: RequestHandler // Custom 404 handler
errorHandler?: (err: Error) => Response | Promise<Response> // Error handler
port?: number // Port number (for reference)
cacheSize?: number // Max entries per HTTP method in the route cache (default: 1000)
}Note on
cacheSize: The router uses an LRU-style cache for resolved routes. When the cache exceedscacheSizeentries for a given HTTP method, the oldest entry is evicted. The default of1000is suitable for most applications. Increase it for APIs with many dynamic routes; decrease it to save memory in constrained environments.
The ZeroRequest extends the standard Request with additional properties:
type ZeroRequest = Request & {
params: Record<string, string> // URL parameters
query: Record<string, string> // Query string parameters
ctx?: Record<string, any> // Custom context (set by middleware)
}// HTTP Methods
router.get(pattern, ...handlers)
router.post(pattern, ...handlers)
router.put(pattern, ...handlers)
router.patch(pattern, ...handlers)
router.delete(pattern, ...handlers)
router.head(pattern, ...handlers)
router.options(pattern, ...handlers)
router.connect(pattern, ...handlers)
router.trace(pattern, ...handlers)
// Generic method
router.on(method, pattern, ...handlers)
// All methods
router.all(pattern, ...handlers)// Global middleware
router.use((req, next) => {
// Middleware logic
return next()
})
// Path-specific middleware
router.use('/api/*', (req, next) => {
// API-specific middleware
return next()
})
// Multiple middlewares
router.use(authMiddleware, loggingMiddleware, (req, next) => next())import http, {ZeroRequest, StepFunction} from '0http-bun'
const {router} = http({
errorHandler: (err: Error) => {
return Response.json({error: err.message}, {status: 500})
},
})
// Logging middleware
router.use((req: ZeroRequest, next: StepFunction) => {
console.log(`${req.method} ${req.url}`)
return next()
})
// JSON body parser middleware for POST/PUT
router.use('/api/*', async (req: ZeroRequest, next: StepFunction) => {
if (req.method === 'POST' || req.method === 'PUT') {
try {
req.ctx = {...req.ctx, body: await req.json()}
} catch (err) {
return Response.json({error: 'Invalid JSON'}, {status: 400})
}
}
return next()
})
// Routes
router.get('/api/users', () => {
return Response.json([
{id: 1, name: 'John'},
{id: 2, name: 'Jane'},
])
})
router.get('/api/users/:id', (req: ZeroRequest) => {
const {id} = req.params
return Response.json({id: Number(id), name: 'User'})
})
router.post('/api/users', (req: ZeroRequest) => {
const userData = req.ctx?.body
return Response.json({id: Date.now(), ...userData}, {status: 201})
})
router.delete('/api/users/:id', (req: ZeroRequest) => {
const {id} = req.params
return Response.json({deleted: id})
})
// Start server
Bun.serve({
port: 3000,
fetch: router.fetch,
})0http-bun includes a comprehensive middleware system with built-in middlewares for common use cases:
📦 Note: Starting with v1.2.2, some middleware dependencies are optional. Install only what you need:
jose(JWT),pino(Logger),prom-client(Prometheus).
- Body Parser - Automatic request body parsing (JSON, form data, text)
- CORS - Cross-Origin Resource Sharing with flexible configuration
- JWT Authentication - JSON Web Token authentication and authorization
- Logger - Request logging with multiple output formats
- Rate Limiting - Flexible rate limiting with sliding window support
- Prometheus Metrics - Export metrics for monitoring and alerting
// Import middleware functions from the middleware module
const {
createCORS,
createLogger,
createBodyParser,
createJWTAuth,
createRateLimit,
} = require('0http-bun/lib/middleware')
const {router} = http()
// Apply middleware stack
router.use(createCORS()) // Enable CORS
router.use(createLogger()) // Request logging
router.use(createBodyParser()) // Parse request bodies
router.use(createRateLimit({max: 100})) // Rate limiting
// Protected routes
router.use('/api/*', createJWTAuth({secret: process.env.JWT_SECRET}))📖 Complete Middleware Documentation
The default error handler returns a generic "Internal Server Error" response (HTTP 500) and logs the full error to console.error. This prevents leaking stack traces or internal details to clients.
You can provide a custom errorHandler for more control:
import http, {ZeroRequest} from '0http-bun'
const {router} = http({
errorHandler: (err: Error) => {
console.error('Application error:', err)
// Custom error responses based on error type
if (err.name === 'ValidationError') {
return Response.json(
{error: 'Validation failed', details: err.message},
{status: 400},
)
}
return Response.json({error: 'Internal server error'}, {status: 500})
},
defaultRoute: () => {
return Response.json({error: 'Route not found'}, {status: 404})
},
})
// Errors thrown in both sync and async handlers are caught automatically
router.get('/api/risky', async (req: ZeroRequest) => {
const data = await fetchExternalData() // async errors are caught too
if (!data) {
throw new Error('Data not found')
}
return Response.json(data)
})Async error handling: Errors thrown or rejected in async middleware/handlers are automatically caught and forwarded to the
errorHandler. You do not need to wrap every handler in try/catch.
0http-bun is designed with security-first principles and includes comprehensive protection against common web vulnerabilities. The core framework and middleware have been thoroughly penetration-tested and hardened.
- Size Limits: Configurable limits prevent memory exhaustion attacks
- ReDoS Protection: Restrictive regex patterns prevent Regular Expression DoS
- JSON Security: String-aware nesting depth validation and safe parsing
- Parameter Validation: Maximum parameter counts and length restrictions
- Filename Sanitization: Multipart file uploads are sanitized to prevent path traversal (directory separators,
.., null bytes are stripped;originalNamepreserved for reference)
- Prototype Pollution Protection: Filters dangerous keys (
__proto__,constructor,prototype) in body parser, multipart parser, and URL-encoded parser usingObject.create(null)for safe objects - Timing Attack Prevention: API key comparisons use
crypto.timingSafeEqual() - Algorithm Confusion Prevention: JWT middleware rejects mixed symmetric/asymmetric algorithm configurations
- Cache Exhaustion Prevention: LRU-style route cache with configurable
cacheSizelimit (default: 1000) - Memory Exhaustion Prevention: Strict size limits, sliding window rate limiter with
maxKeyseviction, and automatic cleanup intervals - Route Filter Bypass Prevention: URL path normalization (double-slash collapse, URI decoding,
%2Fpreservation) - Frozen Route Params: Parameterless routes receive an immutable
Object.freeze({})to prevent cross-request data leakage
- Generic Error Responses: Default error handler returns
"Internal Server Error"without exposing stack traces orerr.message - Server-Side Logging: Full error details logged via
console.errorfor debugging - Async Error Catching: Rejected promises from async middleware are automatically caught and forwarded to the error handler
- Unified JWT Errors: JWT signature/expiry/claim validation failures return
"Invalid or expired token"regardless of the specific failure reason
- JWT Security: Default algorithms restricted to
['HS256']; algorithm confusion prevented - Timing-Safe API Keys: All API key comparisons use constant-time comparison
- Path Exclusion Security: Uses exact match or path boundary checking (
path + '/') instead of prefix matching - Optional Mode Visibility: When
optional: true, invalid tokens setreq.ctx.authErrorandreq.ctx.authAttemptedfor downstream inspection - Minimal Token Exposure: Raw JWT token is no longer stored on the request context
- Secure Key Generation: Default key generator uses
req.ip || req.remoteAddress || req.socket?.remoteAddress || 'unknown'— proxy headers are not trusted by default - No Store Injection: Rate limit store is always the constructor-configured instance (no
req.rateLimitStoreoverride) - Bounded Memory: Sliding window rate limiter enforces
maxKeys(default: 10,000) with periodic cleanup - Synchronous Increment:
MemoryStore.incrementis synchronous to eliminate TOCTOU race conditions - Configurable Limits: Flexible rate limiting with skip functions and path exclusion
- Null Origin Rejection:
nulland missing origins are rejected before calling validator functions or checking arrays, preventing sandboxed iframe bypass - Conditional Headers: CORS headers (methods, allowed headers, credentials, exposed headers) are only set when the origin is actually allowed
- Vary Header:
Vary: Originis set for all non-wildcard origins to prevent CDN cache poisoning - Credential Safety: Prevents wildcard origins with credentials
// Secure server configuration
const {router} = http({
cacheSize: 500, // Limit route cache for constrained environments
errorHandler: (err: Error) => {
// Never expose stack traces in production
return Response.json({error: 'Internal server error'}, {status: 500})
},
defaultRoute: () => {
return Response.json({error: 'Not found'}, {status: 404})
},
})
// Apply security middleware stack
router.use(
createCORS({
origin: ['https://yourdomain.com'], // Restrict origins — null origins are rejected
credentials: true,
}),
)
router.use(
createRateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100,
// Behind a reverse proxy? Provide a custom keyGenerator:
// keyGenerator: (req) => req.headers.get('x-forwarded-for') || req.ip || 'unknown',
}),
)
router.use(
'/api/*',
createJWTAuth({
secret: process.env.JWT_SECRET,
algorithms: ['HS256'], // Default — explicit for clarity
// For RS256, use jwksUri instead of secret:
// jwksUri: 'https://your-idp.com/.well-known/jwks.json',
// algorithms: ['RS256'],
}),
)
// Secure body parsing
router.use(
createBodyParser({
json: {limit: '10mb'},
urlencoded: {limit: '10mb'},
multipart: {limit: '50mb'},
}),
)0http-bun provides built-in security monitoring capabilities:
// Security logging with request context
router.use(
createLogger({
serializers: {
req: (req) => ({
method: req.method,
url: req.url,
ip:
req.ip || req.remoteAddress || req.socket?.remoteAddress || 'unknown',
userAgent: req.headers.get('user-agent'),
}),
},
}),
)
// Prometheus metrics for security monitoring
router.use(
createPrometheusMetrics({
prefix: 'http_',
labels: ['method', 'route', 'status_code'],
}),
)- Environment Variables: Store secrets in environment variables, never in code
- HTTPS Only: Always use HTTPS in production with proper TLS configuration
- Reverse Proxy Configuration: If behind a reverse proxy, always provide a custom
keyGeneratorfor rate limiting that reads the appropriate header (e.g.,X-Forwarded-For) - Algorithm Explicitness: Always explicitly set JWT
algorithms— do not rely on defaults - Input Validation: Validate and sanitize all user inputs
- Regular Updates: Keep dependencies updated and run security audits
- Monitoring: Implement logging and monitoring for security events
Security is a continuous process. While 0http-bun provides strong security foundations, always follow security best practices and conduct regular security assessments for your applications.
0http-bun is designed for high performance with Bun's native capabilities:
- Minimal overhead: Direct use of Web APIs
- Efficient routing: Based on the proven
trouterlibrary - Fast parameter parsing: Optimized URL parameter extraction with caching
- Query string parsing: Uses
fast-querystringfor optimal performance - Memory efficient: LRU-style route caching with configurable
cacheSizelimit, immutable shared objects, and minimal allocations - URL normalization: Single-pass URL parsing with path normalization (double-slash collapse, URI decoding)
Run benchmarks with:
bun run benchPerformance characteristics will vary based on your specific use case and middleware stack.
Full TypeScript support is included with comprehensive type definitions:
// Main framework types
import {
ZeroRequest,
StepFunction,
RequestHandler,
IRouter,
IRouterConfig,
} from '0http-bun'
// Middleware-specific types
import {
LoggerOptions,
JWTAuthOptions,
APIKeyAuthOptions,
RateLimitOptions,
CORSOptions,
BodyParserOptions,
MemoryStore,
} from '0http-bun/lib/middleware'
// Example typed middleware
const customMiddleware: RequestHandler = (
req: ZeroRequest,
next: StepFunction,
) => {
req.ctx = req.ctx || {}
req.ctx.timestamp = Date.now()
return next()
}
// Example typed route handler
const typedHandler = (req: ZeroRequest): Response => {
return Response.json({
params: req.params,
query: req.query,
context: req.ctx,
})
}0http-bun is trusted by developers for production workloads thanks to its comprehensive feature set:
- Body Parser: JSON, URL-encoded, multipart, and text parsing with security
- Authentication: JWT and API key authentication with flexible validation
- CORS: Cross-origin resource sharing with dynamic origin support
- Rate Limiting: Sliding window rate limiting with memory-efficient storage
- Logging: Structured logging with Pino integration and request tracing
- Metrics: Prometheus metrics export for monitoring and alerting
- TypeScript Support: Full type definitions and IntelliSense
- Error Handling: Comprehensive error management with custom handlers; async errors caught automatically
- Request Context: Flexible context system for middleware data sharing
- Parameter Parsing: Automatic URL parameter and query string parsing
- Route Caching: LRU-style caching with configurable
cacheSizefor bounded memory usage
- Environment Agnostic: Works with any Bun deployment platform
- Minimal Dependencies: Small attack surface with carefully selected dependencies
- Memory Efficient: Optimized for serverless and containerized deployments
- Scalable Architecture: Designed for horizontal scaling and load balancing
0http-bun consistently outperforms other frameworks in Bun environments:
| Framework | Requests/sec | Memory Usage | Latency (p95) |
|---|---|---|---|
| 0http-bun | ~85,000 | ~45MB | ~2.1ms |
| Express | ~42,000 | ~68MB | ~4.8ms |
| Fastify | ~78,000 | ~52MB | ~2.4ms |
| Hono | ~82,000 | ~48MB | ~2.2ms |
Benchmarks run on Bun v1.2.2 with simple JSON response routes. Results may vary based on hardware and configuration.
- 📚 Comprehensive Documentation: Detailed guides and API reference
- 🔧 Active Development: Regular updates and feature improvements
- 🐛 Issue Tracking: Responsive bug reports and feature requests
- 💬 Community Discussions: GitHub Discussions for questions and ideas
- 🎯 Production Proven: Used in production by companies worldwide
This release addresses 43 vulnerabilities (6 Critical, 13 High, 13 Medium, 7 Low, 4 Info) identified in a comprehensive penetration test. All 43 issues have been resolved.
| Change | Old Behavior | New Behavior |
|---|---|---|
| Rate limit key generator | Trusted X-Forwarded-For, X-Real-IP, CF-Connecting-IP proxy headers |
Uses req.ip || req.remoteAddress || 'unknown' only. Supply a custom keyGenerator if behind a reverse proxy. |
| JWT default algorithms | ['HS256', 'RS256'] |
['HS256'] only. Mixed symmetric + asymmetric algorithms throw an error. Explicitly set algorithms: ['RS256'] if using RSA keys. |
| Default error handler | Returned err.message to the client in the response body |
Returns generic "Internal Server Error". Full error logged server-side via console.error. |
parseLimit validation |
Silently returned 1MB default for false, null, objects |
Throws TypeError for unexpected types. |
| JWT token in context | req.jwt.token and req.ctx.jwt.token contained the raw JWT string |
Raw token no longer stored on the request context. Only payload and header are available. |
| JWT module exports | Exported internal functions (extractToken, handleAuthError, extractTokenFromHeader, etc.) |
Only exports createJWTAuth, createAPIKeyAuth, and API_KEY_SYMBOL. Internal helpers are no longer exposed. |
| Rate limit store override | req.rateLimitStore could override the configured store at runtime |
Always uses the constructor-configured store. req.rateLimitStore has no effect. |
| API key in context | req.apiKey / req.ctx.apiKey contained the raw API key |
Now stores a masked version (xxxx****xxxx). Raw key available via req[API_KEY_SYMBOL]. |
| Empty JSON body | Empty/whitespace JSON body silently returned {} |
Now sets req.body to undefined. Applications must handle undefined explicitly. |
- LRU route cache with configurable
cacheSize(default: 1000) — prevents unbounded memory growth from cache poisoning attacks. - URL path normalization — double slashes collapsed, URI-decoded (preserving
%2F), preventing route filter bypass via//adminor%2e%2epaths. - Immutable empty params —
Object.freeze({})prevents cross-request data leakage on parameterless routes. router.use()return fix —return thisin arrow function corrected toreturn routerfor proper chaining.- Query prototype pollution protection — dangerous keys (
__proto__,constructor,prototype) are filtered from parsed query strings, mirroring existing route params protection.
- Async error handling — rejected promises from async middleware are now caught via
.catch()and forwarded to theerrorHandler. Previously, they were unhandled.
- String-aware JSON nesting depth scanner — brace characters inside JSON strings no longer count toward nesting depth, fixing a bypass where
{"key": "{{{..."}could evade the depth check. - Custom
jsonParserenforces size limits — size validation runs before the custom parser function is called. - Prototype pollution protection for multipart — uses
Object.create(null)for body/files objects and blocklists dangerous property names. - Multipart filename sanitization — strips
.., path separators (/,\), null bytes, and leading dots. The original filename is preserved infile.originalName. - Strict content-type matching — JSON parser matches
application/jsononly (wasapplication/which matchedapplication/xml,application/octet-stream, etc.). parseLimittype validation — throwsTypeErroron unexpected input types instead of silently defaulting.- Empty JSON body handling — empty or whitespace-only JSON bodies now set
req.bodytoundefinedinstead of silently returning{}. (Breaking change) - Raw body via Symbol — raw body text is now stored via
Symbol.for('0http.rawBody')(RAW_BODY_SYMBOL) instead ofreq._rawBodyText, preventing accidental serialization/logging. The symbol is exported from the body parser module.
- Timing-safe API key comparison — all API key comparisons use
crypto.timingSafeEqual()with constant-time length mismatch handling. - Algorithm confusion prevention — throws if both symmetric (
HS*) and asymmetric (RS*/ES*/PS*) algorithms are configured. - Secure path exclusion — exact match or
path + '/'boundary checking replaces prefix matching (prevents/healthcheckbypassing/healthexclusion). - Optional mode transparency — when
optional: trueand a token is invalid, setsreq.ctx.authErrorandreq.ctx.authAttempted = trueinstead of silently proceeding. - Unified error messages — JWT signature/expiry/claim validation failures return
"Invalid or expired token"to prevent oracle attacks. Distinct messages are used for missing tokens and API key failures. - Safe option merging —
...jwtOptionsspread applied first; security-critical options (algorithms,audience,issuer) override after. - Validator call signature — always calls
apiKeyValidator(apiKey, req)regardless ofFunction.lengtharity. - Reduced export surface — only
createJWTAuthandcreateAPIKeyAuthare exported. - Token type validation — new
requiredTokenTypeoption validates the JWTtypheader claim (case-insensitive). Rejects tokens with missing or incorrect type when configured. - API key via Symbol — raw API key available via
req[API_KEY_SYMBOL](exportedSymbol.for('0http.apiKey')).req.apiKeyandreq.ctx.apiKeynow store a masked version (xxxx****xxxx). (Breaking change) - Error logging in auth handler — empty
catchblocks inhandleAuthErrornow log errors viaconsole.errorfor debugging visibility.
- Secure default key generator — uses
req.ip || req.remoteAddress || 'unknown'instead of trusting proxy headers. - Sliding window memory bounds —
maxKeysoption (default: 10,000) with periodic cleanup viasetInterval+unref(). - Synchronous
MemoryStore.increment— eliminates TOCTOU race condition in the fixed-window store. - Exact path exclusion —
excludePathsuses exact or boundary matching. - Configurable header disclosure —
standardHeadersnow acceptstrue(full headers, default),false(no headers), or'minimal'(onlyRetry-Afteron 429 responses) to control rate limit information disclosure. - Unique unknown keys — when no IP is available, the default key generator now creates unique per-request keys instead of sharing a single
'unknown'bucket, preventing shared-bucket DoS.
- Null origin rejection —
null/missing origins rejected before calling validator functions or checking arrays, preventing sandboxed iframe bypass. - Conditional CORS headers — headers only set when the origin is actually allowed (previously leaked method/header lists even on rejected origins).
Vary: Origin— set for all non-wildcard origins (previously only set for function/array origins).- Single allowedHeaders resolution —
allowedHeadersfunction is now resolved once per preflight request instead of multiple times, preventing inconsistency.
- Middleware dependencies (
jose,pino,prom-client) made optional with lazy loading. - Prometheus metrics middleware added.
- Logger middleware added.
The default keyGenerator no longer reads proxy headers. If your application runs behind a reverse proxy (nginx, Cloudflare, AWS ALB, etc.), you must provide a custom keyGenerator:
router.use(
createRateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
keyGenerator: (req) => {
// Trust the header your reverse proxy sets
return (
req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||
req.ip ||
'unknown'
)
},
}),
)If you were relying on the default ['HS256', 'RS256'] algorithm list, you must now be explicit:
// For HMAC (symmetric) secrets:
createJWTAuth({
secret: process.env.JWT_SECRET,
algorithms: ['HS256'], // This is now the default
})
// For RSA (asymmetric) keys:
createJWTAuth({
jwksUri: 'https://your-idp.com/.well-known/jwks.json',
algorithms: ['RS256'], // Must be explicit — mixing with HS256 will throw
})If you relied on err.message being returned to clients from the default error handler, provide a custom errorHandler:
const {router} = http({
errorHandler: (err: Error) => {
// Old behavior (NOT recommended for production):
return new Response(err.message, {status: 500})
},
})If your code passes non-string/non-number values to parseLimit (e.g., false, null, objects), update it to pass a valid value:
// Before (silently defaulted to 1MB):
createBodyParser({json: {limit: someConfig.limit}}) // someConfig.limit might be null
// After (throws TypeError):
createBodyParser({json: {limit: someConfig.limit || '1mb'}}) // Provide a fallbackIf you accessed the raw JWT token string via req.jwt.token or req.ctx.jwt.token, note that only payload and header are now available:
// Before:
const rawToken = req.jwt.token // No longer available
// After:
const payload = req.jwt.payload // Decoded payload
const header = req.jwt.header // Protected headerIf you accessed the raw API key via req.apiKey or req.ctx.apiKey, note that these now contain a masked version. Use the exported API_KEY_SYMBOL for programmatic access:
import {API_KEY_SYMBOL} from '0http-bun/lib/middleware/jwt-auth'
// Before:
const rawKey = req.apiKey // Was the raw API key, now masked (xxxx****xxxx)
// After:
const rawKey = req[API_KEY_SYMBOL] // Symbol.for('0http.apiKey')
const maskedKey = req.apiKey // 'xxxx****xxxx' (safe for logging)If your code relied on empty JSON request bodies being parsed as {}, update it to handle undefined:
// Before (empty body → {}):
router.post('/api/data', (req) => {
const keys = Object.keys(req.body) // Always worked
})
// After (empty body → undefined):
router.post('/api/data', (req) => {
const body = req.body || {}
const keys = Object.keys(body) // Handle undefined
})If you accessed raw body text via req._rawBodyText, use the exported RAW_BODY_SYMBOL instead:
import {RAW_BODY_SYMBOL} from '0http-bun/lib/middleware/body-parser'
// Before:
const rawBody = req._rawBodyText // Public string property
// After:
const rawBody = req[RAW_BODY_SYMBOL] // Symbol.for('0http.rawBody')MIT
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
# Clone the repository
git clone https://github.com/BackendStack21/0http-bun.git
cd 0http-bun
# Install dependencies
bun install
# Run tests
bun test
# Run benchmarks
bun run bench
# Format code
bun run format- 0http - The original inspiration
- Bun - The JavaScript runtime this framework is built for
- Trouter - Fast routing library used under the hood
- Fast QueryString - Optimized query string parsing