From harness-claude
Builds low-level HTTP servers using Node.js http module with routing, JSON body parsing, middleware composition, and graceful shutdown. Use for simple servers, microservices, or understanding framework primitives.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Build low-level HTTP servers with Node.js http module and middleware pattern
Builds HTTP servers with Bun.serve, covering request handling (methods, paths, queries, headers), body parsing (JSON, form, text), responses (JSON, HTML, files, streams), simple routing, and error handling.
Implements Node.js backend patterns with Express/Fastify for middleware, error handling, auth, DB integration, REST/GraphQL APIs, microservices, and WebSockets.
Share bugs, ideas, or general feedback.
Build low-level HTTP servers with Node.js http module and middleware pattern
import { createServer, IncomingMessage, ServerResponse } from 'node:http';
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello, world!' }));
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
const server = createServer((req, res) => {
const url = new URL(req.url!, `http://${req.headers.host}`);
if (req.method === 'GET' && url.pathname === '/api/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok' }));
return;
}
if (req.method === 'GET' && url.pathname === '/api/users') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(users));
return;
}
res.writeHead(404);
res.end('Not Found');
});
async function parseBody(req: IncomingMessage): Promise<unknown> {
return new Promise((resolve, reject) => {
const chunks: Buffer[] = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const body = Buffer.concat(chunks).toString();
try {
resolve(JSON.parse(body));
} catch {
reject(new Error('Invalid JSON'));
}
});
req.on('error', reject);
});
}
// Usage in handler
if (req.method === 'POST' && url.pathname === '/api/users') {
const body = await parseBody(req);
// process body...
}
type Handler = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
function compose(...handlers: Handler[]) {
return (req: IncomingMessage, res: ServerResponse) => {
let i = 0;
function next() {
if (i < handlers.length) handlers[i++](req, res, next);
}
next();
};
}
const logger: Handler = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
const cors: Handler = (req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
next();
};
const server = createServer(compose(logger, cors, router));
const server = createServer(handler);
server.listen(3000);
process.on('SIGTERM', () => {
server.close(() => {
console.log('Server shut down gracefully');
process.exit(0);
});
setTimeout(() => {
console.error('Forced shutdown after timeout');
process.exit(1);
}, 10_000);
});
The node:http module provides the lowest-level HTTP handling in Node.js. Frameworks like Express, Fastify, and Hono build on top of it.
IncomingMessage is a Readable stream. The request body is not buffered automatically — you must consume the stream manually. This is by design for memory efficiency with large uploads.
ServerResponse is a Writable stream. Calling res.end() finishes the response. Calling res.write() before res.end() enables streaming responses.
Keep-alive: Node.js HTTP server keeps connections alive by default (HTTP/1.1). Set server.keepAliveTimeout to control how long idle connections stay open.
Trade-offs:
http module gives full control — but lacks routing, middleware, and body parsing that frameworks providehttps://nodejs.org/api/http.html