@seahax/espresso
v0.3.2
Published
A lightweight, type-safe Node.js HTTP server framework with routing, filtering, and error handling.
Downloads
23
Readme
@seahax/espresso
A lightweight, type-safe Node.js HTTP server framework with routing, filtering, and error handling.
Installation
npm install @seahax/espressoQuick Start
import { createApplication } from '@seahax/espresso';
const app = createApplication();
app.addRoute('GET', '/', (request, response) => {
response.sendJson({ message: 'Hello, World!' });
});
app.listen({ port: 3000 });Core Concepts
Application
The main entry point for creating HTTP servers with routing, filtering, and error handling.
import { createApplication } from '@seahax/espresso';
const app = createApplication({
headers: { 'x-powered-by': 'espresso' },
compression: true
});Routes
Define how HTTP requests are handled based on method and path patterns.
import { createRoute } from '@seahax/espresso';
// Inline route definition
app.addRoute('GET', '/users/{id}', async (request, response) => {
const { id } = await request.pathParameters();
response.sendJson({ userId: id });
});
// Pre-defined route
const userRoute = createRoute('GET', '/users/{id}', async (request, response) => {
const { id } = await request.pathParameters();
response.sendJson({ userId: id });
});
app.addRoute(userRoute);
// Multiple methods and paths
app.addRoute(['GET', 'POST'], ['/api/users/{id}', '/users/{id}'], (request, response) => {
const { id } = await request.pathParameters();
response.sendJson({ userId: id });
});
// Multi-segment route parameter
app.addRoute('GET', '/files/{path+}', async (request, response) => {
const { path } = await request.pathParameters();
response.sendJson({ filePath: path });
});Controllers
Group related routes, filters, and error handlers with optional path prefixes.
import { createController } from '@seahax/espresso';
const apiController = createController('/api');
apiController.addRoute('GET', '/users', (request, response) => {
response.sendJson({ users: [] });
});
apiController.addRoute('POST', '/users', async (request, response) => {
const userData = await request.body();
response.sendJson({ created: true });
});
app.addController(apiController);
// Routes are now available at /api/usersRequest Handling
Access request data with built-in validation support.
app.addRoute('POST', '/users/{id}', async (request, response) => {
// Path parameters (from route like /users/{id})
const pathParams = await request.pathParameters();
// With schema validation (requires @standard-schema compatible schema)
// const validatedPathParams = await request.pathParameters(pathParamsSchema);
// Query parameters
const queryParams = await request.queryParameters();
// With schema validation
// const validatedQueryParams = await request.queryParameters(queryParamsSchema);
// Headers
const headers = await request.headers();
// With schema validation
// const validatedHeaders = await request.headers(headersSchema);
// Cookies
const cookies = await request.cookies();
// With schema validation
// const validatedCookies = await request.cookies(cookiesSchema);
// Request body (parsed based on content-type)
const body = await request.body();
// With schema validation
// const validatedBody = await request.body(bodySchema);
response.sendJson({ success: true });
});Response Handling
Send different types of responses with built-in compression and caching support.
app.addRoute('GET', '/api/data', async (request, response) => {
// Text/HTML response
response.send('Hello, World!');
// JSON response
response.sendJson({ data: 'value' });
// File response
response.sendFile('/public', 'index.html');
// Set status code
response.setStatus(201).sendJson({ created: true });
// Set headers
response
.setHeader('cache-control', 'max-age=3600')
.sendJson({ data: 'cached' });
});Filters
Apply middleware-like logic to requests before they reach route handlers.
import { createFilter } from '@seahax/espresso';
// Authentication filter
const authFilter = createFilter(async (request, response) => {
const { authorization } = await request.headers();
if (!authorization) {
response.setStatus(401).sendJson({ error: 'Unauthorized' });
// Response sent, route handler won't be called
}
});
app.addFilter(authFilter);Error Handlers
Handle errors thrown by filters or route handlers.
import { createErrorHandler, RequestValidationError } from '@seahax/espresso';
const errorHandler = createErrorHandler(async ({ error, request, response }) => {
console.error('Request error:', error);
if (!response.sent) {
response.setStatus(500).sendJson({
error: 'Internal Server Error',
message: error.message
});
}
});
// Error handler that skips remaining handlers for specific errors
const validationErrorHandler = createErrorHandler(async ({ error, request, response, skipRemainingHandlers }) => {
if (error instanceof RequestValidationError) {
response.setStatus(400).sendJson({
error: 'Request Validation Error',
issues: error.issues
});
// Skip remaining error handlers since we've handled this error
skipRemainingHandlers();
}
});
app.addErrorHandler(validationErrorHandler);
app.addErrorHandler(errorHandler); // This won't run for RequestValidationErrorsBody Parsers
Handle different content types in request bodies. By default, espresso includes parsers for:
application/jsonanddefault- JSON parsingapplication/x-www-form-urlencoded- URL-encoded form datatext/plain- Plain text
import { parseJson, parseText, parseUrlEncoded } from '@seahax/espresso';
// Add custom parser for XML
app.addParser('application/xml', async (body) => {
// Parse XML string to object
return parseXml(body);
});
// Disable JSON parsing (including as the default)
app.addParser(['application/json', 'default'], false);Health Check Routes
Create health check endpoints with automatic status monitoring.
import { createHealthRoute } from '@seahax/espresso';
const healthRoute = createHealthRoute({
database: async () => {
// Return true if database is healthy
return await checkDatabaseConnection();
},
redis: {
check: async () => await checkRedisConnection(),
intervalSeconds: 60,
initialDelaySeconds: 10
}
}, {
path: '/health',
onCheck: (name, result, error) => {
if (!result) {
console.error(`Health check ${name} failed:`, error);
}
}
});
app.addRoute(healthRoute);Info Routes
Create application info endpoints with caching and conditional responses.
import { createInfoRoute } from '@seahax/espresso';
// Custom path and options
const apiInfoRoute = createInfoRoute({
name: 'My API',
version: '1.0.0',
build: process.env.BUILD_ID
}, {
// defaults to /_info
path: '/api/info',
});
app.addRoute(apiInfoRoute);
// Available at GET /api/infoSPA Routes
Create routes for serving single-page applications with fallback handling.
import { createSpaRoute } from '@seahax/espresso';
// Basic SPA route
const spaRoute = createSpaRoute('/public');
app.addRoute(spaRoute);
// SPA with custom path and options
const spaRoute = createSpaRoute('/admin-dist', {
path: '/app',
index: 'index.html',
headers: (filename) => ({
'cache-control': filename.startsWith('assets/') ? 'max-age=86400' : 'no-cache'
})
});
app.addRoute(spaRoute);Connect Middleware
Use existing Connect middleware.
import { createMiddlewareFilter } from '@seahax/espresso';
import helmet from 'helmet';
import morgan from 'morgan';
const helmetFilter = createMiddlewareFilter(helmet());
const morganFilter = createMiddlewareFilter(morgan('combined'));
app.addFilter(helmetFilter);
app.addFilter(morganFilter);Server Lifecycle
Control server startup and shutdown.
const app = createApplication();
// Basic listen
const server = app.listen({ port: 3000 });
// Listen with custom server
import { createServer } from 'https';
const httpsServer = createServer(sslOptions);
app.listen({
server: httpsServer,
port: 443,
onListening: (url, server) => {
console.log(`Server running at ${url}`);
}
});
// Graceful shutdown
process.on('SIGTERM', () => {
app.close();
});
// Listen for events
app.on('listening', (url, server) => {
console.log(`Server started at ${url}`);
});
app.on('closing', () => {
console.log('Server close method called');
});
app.on('close', () => {
console.log('Server closed');
});API Reference
Application
createApplication(options?)- Create a new application instanceapp.addRoute(route)- Add a pre-defined routeapp.addRoute(method, path, handler)- Add a route inlineapp.addController(controller)- Add a controllerapp.addFilter(filter)- Add a request filterapp.addErrorHandler(handler)- Add an error handlerapp.addParser(contentType, parser)- Add a body parserapp.addDefaultHandler(handler)- Add a fallback handlerapp.listen(options?)- Start the serverapp.close()- Stop the server
Controller
createController(prefix?)- Create a controller with optional path prefixcontroller.addRoute(...)- Add routes (same API as application)controller.addController(controller)- Add nested controllerscontroller.addFilter(filter)- Add controller-scoped filterscontroller.addErrorHandler(handler)- Add controller-scoped error handlers
Route
createRoute(method, path, handler)- Create a route definitioncreateHealthRoute(checks, options?)- Create health check routecreateInfoRoute(info, options?)- Create info endpoint routecreateSpaRoute(root, options?)- Create single-page application route
Request
request.pathParameters(schema?)- Get path parametersrequest.queryParameters(schema?)- Get query parametersrequest.headers(schema?)- Get headersrequest.cookies(schema?)- Get cookiesrequest.body(schema?)- Get parsed bodyrequest.method- HTTP methodrequest.path- Request pathrequest.url- Full URLrequest.protocol- 'http' or 'https'
Response
response.send(body?, options?)- Send responseresponse.sendJson(body, options?)- Send JSON responseresponse.sendFile(root, filename, options?)- Send fileresponse.setStatus(code)- Set status coderesponse.setHeader(name, value)- Set headerresponse.setHeaders(headers)- Set multiple headersresponse.sent- Whether response has been sentresponse.finished- Whether response is finished
Utilities
createFilter(fn)- Create a filter functioncreateMiddlewareFilter(middleware)- Create a filter function from Connect middlewarecreateErrorHandler(fn)- Create an error handler functioncreateMiddlewareErrorHandler(middleware)- Create an error handler function from connect middlewareparseJson(body)- Parse JSON bodyparseText(body)- Parse text bodyparseUrlEncoded(body)- Parse URL encoded body
