Node.js HTTP adapter that bridges Node.js IncomingMessage and ServerResponse with the Ingest framework, enabling seamless integration with Node.js HTTP servers.
import HttpAdapter from '@stackpress/ingest/http/Adapter';
import { createServer } from 'node:http';
// Static usage
const server = createServer(async (req, res) => {
await HttpAdapter.plug(context, req, res);
});
// Instance usage
const adapter = new HttpAdapter(context, req, res);
await adapter.plug();- Plugging HTTP Requests
- Methods
- Request Processing Flow
- Body Loading
- Response Dispatching
- Integration Examples
- Static Functions
- Best Practices
The following example shows how to handle HTTP requests using the static plug method for seamless integration.
import { createServer } from 'node:http';
import { server } from '@stackpress/ingest/http';
const app = server();
const httpServer = createServer(async (req, res) => {
await HttpAdapter.plug(app, req, res);
});
// With custom action
const httpServer2 = createServer(async (req, res) => {
await HttpAdapter.plug(app, req, res, 'custom-handler');
});
// With action function
const httpServer3 = createServer(async (req, res) => {
await HttpAdapter.plug(app, req, res, async (req, res, ctx) => {
res.setJSON({ message: 'Custom handler' });
});
});Parameters
| Parameter | Type | Description |
|---|---|---|
context |
HttpServer<C> |
Server context instance |
request |
IncomingMessage |
Node.js HTTP request object |
response |
ServerResponse |
Node.js HTTP response object |
action |
string|HttpAction<C> |
Custom action name or function (optional) |
Returns
A promise that resolves to the ServerResponse object after processing.
The following methods are available when instantiating an HttpAdapter.
The following example shows how to process HTTP requests through the adapter with flexible action handling.
const adapter = new HttpAdapter(context, req, res);
// Process with automatic route detection
await adapter.plug();
// Process with custom action
await adapter.plug('user-login');
// Process with action function
await adapter.plug(async (req, res, ctx) => {
const users = await getUsers();
res.setResults(users);
});Parameters
| Parameter | Type | Description |
|---|---|---|
action |
string|HttpAction<C> |
Custom action name or function (optional) |
Returns
A promise that resolves to the ServerResponse object after processing.
The following example shows how HTTP requests are converted to Ingest Request objects.
const adapter = new HttpAdapter(context, req, res);
const request = adapter.request();
// Access request properties
console.log(request.method); // 'GET', 'POST', etc.
console.log(request.url); // URL object
console.log(request.headers); // Request headers
console.log(request.query); // Query parameters
console.log(request.session); // Session data from cookiesReturns
An Ingest Request object configured for the HTTP request.
The following example shows how HTTP responses are created for Ingest processing.
const adapter = new HttpAdapter(context, req, res);
const response = adapter.response();
// Set response data
response.setJSON({ message: 'Hello World' });
response.setHTML('<h1>Hello World</h1>');
response.setError('Not found', {}, [], 404);
// Dispatch to HTTP response
await response.dispatch();Returns
An Ingest Response object configured for HTTP output.
HttpAdapter follows a structured request processing flow for reliable HTTP request handling.
Convert IncomingMessage to Ingest Request with comprehensive data extraction.
// Convert IncomingMessage to Ingest Request
const request = adapter.request();
// - Extracts HTTP method, URL, headers
// - Parses cookies into session data
// - Converts query parameters to nested object
// - Sets up body loader for POST dataCreate Ingest Response for ServerResponse with proper configuration.
// Create Ingest Response for ServerResponse
const response = adapter.response();
// - Configures response dispatcher
// - Sets up cookie handling
// - Prepares header managementLoad request body asynchronously with content type detection.
// Load request body asynchronously
await request.load();
// - Reads POST data from request stream
// - Parses form data and JSON
// - Handles multipart uploads
// - Enforces size limitsExecute route through Route.emit with complete lifecycle management.
// Execute route through Route.emit
await Route.emit(event, request, response, context);
// - Runs request lifecycle (prepare, process, shutdown)
// - Executes route handlers
// - Handles errors and 404sSend response to client with proper headers and content.
// Send response to client
await response.dispatch();
// - Sets HTTP status code and message
// - Writes cookies to Set-Cookie headers
// - Sends response headers
// - Streams response bodyHttpAdapter provides robust body loading for HTTP requests with automatic parsing and size limits.
Parse request bodies automatically based on content type.
// Body is automatically loaded and parsed
await request.load();
// Access parsed data
const formData = request.post.get(); // Form data
const jsonData = request.data.get(); // Combined data
const rawBody = request.body; // Raw body stringHandle different content types with appropriate parsing strategies.
// Form data (application/x-www-form-urlencoded)
// Content-Type: application/x-www-form-urlencoded
// Body: name=John&email=john@example.com
// Result: { name: 'John', email: 'john@example.com' }
// JSON data (application/json)
// Content-Type: application/json
// Body: {"name":"John","email":"john@example.com"}
// Result: { name: 'John', email: 'john@example.com' }
// Multipart form data (multipart/form-data)
// Handles file uploads and form fieldsEnforce request size limits for security and performance.
// Configure body size limits
const loader = HttpAdapter.loader(request, 1024 * 1024); // 1MB limit
// Size limit enforcement
request.on('data', chunk => {
body += chunk;
if (body.length > maxSize) {
throw new Error(`Request exceeds ${maxSize} bytes`);
}
});HttpAdapter handles various response types and formats with automatic content type detection.
Handle different response types with appropriate content type headers.
// String responses
response.setHTML('<h1>Hello World</h1>');
// Sets Content-Type: text/html
// JSON responses
response.setJSON({ message: 'Success' });
// Sets Content-Type: application/json
// Buffer responses
response.body = Buffer.from('binary data');
// Sends raw binary data
// Stream responses
response.body = fs.createReadStream('file.pdf');
// Pipes file stream to response
// Object responses (automatic JSON)
response.body = { users: [...] };
// Automatically serializes to JSONManage session cookies with automatic serialization and security options.
// Session cookies are automatically handled
response.session.set('user_id', '123');
response.session.set('preferences', JSON.stringify(prefs));
// Cookies are written as Set-Cookie headers
// Set-Cookie: user_id=123; Path=/
// Set-Cookie: preferences={"theme":"dark"}; Path=/Set custom headers for security, caching, and API versioning.
// Custom headers
response.headers.set('X-API-Version', '1.0');
response.headers.set('Cache-Control', 'no-cache');
// Security headers
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('X-Content-Type-Options', 'nosniff');The following examples demonstrate common HttpAdapter integration patterns for real-world applications.
import { createServer } from 'node:http';
import { server } from '@stackpress/ingest/http';
const app = server();
// Define routes
app.get('/users', async (req, res, ctx) => {
const users = await getUsers();
res.setResults(users);
});
app.post('/users', async (req, res, ctx) => {
const userData = req.data.get();
const user = await createUser(userData);
res.setResults(user, 201);
});
// Create HTTP server
const httpServer = createServer(async (req, res) => {
await HttpAdapter.plug(app, req, res);
});
httpServer.listen(3000, () => {
console.log('Server running on port 3000');
});
async function getUsers() {
return [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }];
}
async function createUser(userData: any) {
return { id: Date.now(), ...userData };
}const app = server();
// Request middleware
app.on('request', async (req, res) => {
// CORS headers
res.headers.set('Access-Control-Allow-Origin', '*');
res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
// Request logging
console.log(`${req.method} ${req.url.pathname}`);
return true; // Continue processing
});
// Error handling
app.on('error', async (req, res) => {
console.error('Request error:', res.error);
if (res.code >= 500) {
// Log server errors
logger.error(res.error, { url: req.url.href, method: req.method });
}
return true; // Continue processing
});
const logger = {
error: (message: string, context: any) => {
console.error(message, context);
}
};app.post('/upload', async (req, res, ctx) => {
await req.load(); // Load multipart data
const files = req.post.get('files');
const metadata = req.post.get('metadata');
// Process uploaded files
for (const file of files) {
await saveFile(file);
}
res.setJSON({
message: 'Files uploaded successfully',
count: files.length
});
});
async function saveFile(file: any) {
// File saving logic
console.log(`Saving file: ${file.name}`);
}HttpAdapter provides utility functions for request and response handling with customizable options.
The following example shows how to create a custom body loader with size limits.
import { loader } from '@stackpress/ingest/http/Adapter';
// Create loader with size limit
const bodyLoader = loader(incomingMessage, 1024 * 1024); // 1MB limit
// Use with request
request.loader = bodyLoader;
await request.load();Parameters
| Parameter | Type | Description |
|---|---|---|
resource |
IncomingMessage |
Node.js HTTP request object |
size |
number |
Maximum body size in bytes (default: 0 = no limit) |
Returns
A loader function that reads and parses the request body.
The following example shows how to create a custom response dispatcher with cookie options.
import { dispatcher } from '@stackpress/ingest/http/Adapter';
// Create dispatcher with cookie options
const responseDispatcher = dispatcher({
path: '/',
httpOnly: true,
secure: true,
sameSite: 'strict'
});
// Use with response
response.dispatcher = responseDispatcher;
await response.dispatch();Parameters
| Parameter | Type | Description |
|---|---|---|
options |
CookieOptions |
Cookie configuration options |
Returns
A dispatcher function that writes the response to ServerResponse.
The following best practices ensure robust and secure HTTP adapter implementations.
Implement comprehensive error handling for production reliability.
const httpServer = createServer(async (req, res) => {
try {
await HttpAdapter.plug(app, req, res);
} catch (error) {
console.error('Adapter error:', error);
// Ensure response is sent
if (!res.headersSent) {
res.statusCode = 500;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({
code: 500,
status: 'Internal Server Error',
error: 'Server error occurred'
}));
}
}
});Configure server settings for optimal performance and resource usage.
// Enable keep-alive
httpServer.keepAliveTimeout = 65000;
httpServer.headersTimeout = 66000;
// Set request size limits
const app = server();
app.on('request', async (req, res) => {
const contentLength = parseInt(req.headers.get('content-length') || '0');
if (contentLength > 10 * 1024 * 1024) { // 10MB limit
res.setError('Request too large', {}, [], 413);
return false; // Abort processing
}
return true;
});Implement security headers for protection against common vulnerabilities.
app.on('response', async (req, res) => {
// Security headers
res.headers.set('X-Frame-Options', 'DENY');
res.headers.set('X-Content-Type-Options', 'nosniff');
res.headers.set('X-XSS-Protection', '1; mode=block');
res.headers.set('Strict-Transport-Security', 'max-age=31536000');
return true;
});Implement graceful shutdown for clean server termination.
const httpServer = createServer(async (req, res) => {
await HttpAdapter.plug(app, req, res);
});
process.on('SIGTERM', () => {
console.log('Received SIGTERM, shutting down gracefully');
httpServer.close(() => {
console.log('HTTP server closed');
process.exit(0);
});
});