
Product
Introducing Socket Firewall Enterprise: Flexible, Configurable Protection for Modern Package Ecosystems
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.
@rhinolabs/boilr
Advanced tools
A convention-based Fastify framework with batteries included. Boilr brings Next.js-inspired simplicity and TypeScript type safety to Fastify API development.
# Create a new project using the CLI (recommended)
npm install -g @rhinolabs/boilr-cli
boilr new my-api
cd my-api
npm install
npm run dev
# Or add to an existing project
npm install @rhinolabs/boilr
// server.ts - Your entry point
import { createApp } from '@rhinolabs/boilr';
// Create the application with configuration
const app = createApp({
server: { port: 3000 },
routes: { dir: './routes' },
plugins: {
swagger: {
info: {
title: 'My API',
version: '1.0.0'
}
}
}
});
// Start the server
app.start();
// routes/hello.ts - A simple route
import { z } from 'zod';
import { defineSchema, type GetHandler } from '@rhinolabs/boilr';
export const schema = defineSchema({
get: {
querystring: z.object({
name: z.string().optional()
}),
response: {
200: z.object({
message: z.string()
})
}
}
});
export const get: GetHandler<typeof schema> = async (request, reply) => {
const { name = 'world' } = request.query;
return { message: `Hello, ${name}!` };
};
Boilr automatically maps your directory structure to API routes following Next.js conventions:
routes/
├── index.ts → GET /
├── products/
│ ├── index.ts → GET/POST /products
│ ├── [id].ts → GET/PUT/DELETE /products/:id
│ └── [id]/reviews.ts → GET /products/:id/reviews
├── (admin)/ → (admin) won't affect URL paths
│ └── settings.ts → GET /settings
└── [...catch-all].ts → Catch remaining routes
Define your routes with full type safety using Zod schemas:
// routes/users/[id].ts
import { z } from 'zod';
import { defineSchema, GetHandler, PutHandler } from '@rhinolabs/boilr';
export const schema = defineSchema({
get: {
params: z.object({
id: z.string().transform(val => parseInt(val, 10))
}),
response: {
200: z.object({
id: z.number(),
name: z.string()
})
}
},
put: {
params: z.object({
id: z.string().transform(val => parseInt(val, 10))
}),
body: z.object({
name: z.string().min(1)
}),
response: {
200: z.object({
id: z.number(),
name: z.string(),
updated: z.boolean()
})
}
}
});
// Type-safe GET handler (id is correctly typed as number)
export const get: GetHandler<typeof schema> = async (request, reply) => {
const { id } = request.params;
return { id, name: `User ${id}` };
};
// Type-safe PUT handler (with typed body and params)
export const put: PutHandler<typeof schema> = async (request, reply) => {
const { id } = request.params;
const { name } = request.body;
return { id, name, updated: true };
};
Define handlers for different HTTP methods by exporting named functions:
export async function get(request, reply) { ... } // GET
export async function post(request, reply) { ... } // POST
export async function put(request, reply) { ... } // PUT
export async function patch(request, reply) { ... } // PATCH
export async function del(request, reply) { ... } // DELETE
Customize your application with a flexible configuration system:
const app = createApp({
server: {
port: 8080,
host: '0.0.0.0',
logger: true
},
routes: {
dir: './api',
prefix: '/api/v1'
},
plugins: {
helmet: true,
rateLimit: {
max: 100,
timeWindow: '1 minute'
},
cors: true,
swagger: {
info: {
title: 'My API',
description: 'API documentation',
version: '1.0.0'
}
}
}
});
Boilr automatically adds error response schemas to your Swagger documentation. By default, all routes include a 500 (Internal Server Error) response schema, but you can customize this behavior:
const app = createApp({
exceptions: {
// Customize which error status codes to include by default
defaultErrorStatusCodes: [400, 401, 404, 500],
// Custom error response format
formatter: (exception, request, reply) => ({
success: false,
error: exception.message,
code: exception.statusCode
}),
// Custom error schema for documentation
formatterSchema: z.object({
success: z.boolean(),
error: z.string(),
code: z.number()
})
}
});
Override error schemas for specific routes by adding defaultErrorStatusCodes to your method schemas:
export const schema = defineSchema({
get: {
// Include specific error codes for this endpoint
defaultErrorStatusCodes: [401, 403, 404],
response: {
200: z.object({ data: z.string() })
}
},
post: {
// Disable automatic error schemas for this method
defaultErrorStatusCodes: false,
body: z.object({ name: z.string() }),
response: {
201: z.object({ id: z.number() })
}
}
});
The default error response schema matches the built-in error format:
{
status: number; // HTTP status code
message: string; // Error message
error: string; // Error type (e.g., "NotFound")
details?: unknown; // Optional error details
}
This ensures your API documentation always includes comprehensive error response information, making it easier for API consumers to understand and handle errors properly.
Boilr provides comprehensive error handling with built-in HTTP exception classes and automatic error formatting:
import { NotFoundException } from '@rhinolabs/boilr';
throw new NotFoundException('User not found');
Available Exception Classes:
Client Errors (4xx):
BadRequestException (400) - Invalid request format or parametersUnauthorizedException (401) - Authentication required or invalidForbiddenException (403) - Insufficient permissionsNotFoundException (404) - Resource not foundMethodNotAllowedException (405) - HTTP method not supportedNotAcceptableException (406) - Requested format not acceptableRequestTimeoutException (408) - Request took too longConflictException (409) - Resource conflict or duplicateGoneException (410) - Resource no longer availablePreconditionFailedException (412) - Precondition not metPayloadTooLargeException (413) - Request payload too largeUnsupportedMediaTypeException (415) - Media type not supportedImATeapotException (418) - I'm a teapot (RFC 2324)UnprocessableEntityException (422) - Validation failedValidationException (422) - Validation failed with detailed errorsServer Errors (5xx):
InternalServerErrorException (500) - Internal server errorNotImplementedException (501) - Feature not implementedBadGatewayException (502) - Bad gateway responseServiceUnavailableException (503) - Service temporarily unavailableGatewayTimeoutException (504) - Gateway timeoutHttpVersionNotSupportedException (505) - HTTP version not supportedthrow new NotFoundException('User not found', {
name: 'USER_NOT_FOUND', // Custom error code
details: { userId: id }, // Additional context
cause: originalError // Underlying error
});
import { ValidationException } from '@rhinolabs/boilr';
// Manual validation errors
throw new ValidationException('Validation failed', [
{ field: 'email', message: 'Invalid email format', value: 'invalid-email' },
{ field: 'age', message: 'Must be a positive number', value: -5 }
]);
// Zod validation errors are automatically converted
const result = userSchema.parse(invalidData); // Throws ZodError -> becomes ValidationException
All exceptions are automatically formatted into a consistent JSON response:
{
"status": 404,
"message": "User not found",
"error": "NotFound",
"details": { "userId": "123" }
}
Configure global error handling behavior:
import { createApp } from '@rhinolabs/boilr';
const app = createApp({
exceptions: {
// Custom error formatter
formatter: (exception, request, reply) => ({
success: false,
code: exception.statusCode,
message: exception.message,
timestamp: new Date().toISOString(),
path: request.url,
data: exception.details
}),
// Enable/disable error logging (default: true)
logErrors: true
}
});
Errors are automatically logged with different levels:
Log format includes:
{
"timestamp": "2024-01-01T00:00:00.000Z",
"level": "error",
"message": "User not found",
"status": 404,
"path": "/api/users/123",
"method": "GET",
"details": { "userId": "123" }
}
Check out complete examples:
MIT
FAQs
Convention-based Fastify framework with batteries included
We found that @rhinolabs/boilr demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.

Security News
Open source dashboard CNAPulse tracks CVE Numbering Authorities’ publishing activity, highlighting trends and transparency across the CVE ecosystem.

Product
Detect malware, unsafe data flows, and license issues in GitHub Actions with Socket’s new workflow scanning support.