Restify
Restify is an opinionated Node.js web service framework optimized for building semantically correct RESTful APIs. Unlike more generalized frameworks like Express, Restify focuses purely on API development, offering built-in features for introspection, performance, DTrace support, and robust error handling. It's designed for high-throughput, scalable services and is utilized in large-scale Node.js deployments. The current stable version is 11.2.0, released in August 2023. Major releases, often introducing breaking changes or significant feature updates, occur periodically, with more frequent minor and patch updates addressing bugs and adding smaller features.
Common errors
-
Error: Cannot find module 'bunyan'
cause Upgrading Restify to v9.0.0 or later without updating logging dependencies. Restify switched from Bunyan to Pino for logging.fixUninstall `bunyan` and related Restify Bunyan loggers. Install `pino` and integrate it, possibly using `restify-pino-logger` or configuring Pino directly with `restify.createServer({ log: pinoInstance })`. -
TypeError: next is not a function
cause Attempting to use `next('route-name')` for re-routing after upgrading to Restify v9.0.0+, where this functionality was removed.fixReplace `return next('route-name');` with `res.redirect('/new-route-path');` or implement custom dispatch logic. If an error is intended, pass an `Error` object to `next()`. -
HTTP 413 Request Entity Too Large
cause The request body size exceeds the server's configured limit, often due to large file uploads or extensive data payloads with `bodyParser`.fixIncrease the `maxBodySize` option in your `bodyParser` configuration (e.g., `server.use(restify.plugins.bodyParser({ maxBodySize: 1024 * 1024 * 10 }));` for 10MB). This can also be influenced by server-level configurations like Nginx or cloud load balancers. -
{ "code": "InternalServer", "message": "reached the end of the handler chain without writing a response!" }cause A handler or middleware function completed its execution (e.g., an `async/await` operation finished) without calling `res.send()` or `next()`, leading Restify to believe the request was unhandled.fixEnsure that every handler either calls `res.send()` to terminate the response or `return next();` (or `return next(err);` for errors) to pass control to the next middleware in the chain. Pay close attention to asynchronous operations within handlers.
Warnings
- breaking The `req.log` behavior was modified, no longer overriding existing `req.log` instances if already set during the `.first` middleware chain. The audit plugin also now uses `req.log` directly. This can affect custom logging integrations.
- breaking Support for Node.js 18.x was explicitly added as a breaking change, implying older Node.js versions (e.g., 10.x, 12.x, 14.x, 16.x) may no longer be officially supported or fully compatible. `dtrace-provider` was also bumped, which might affect some environments.
- breaking Restify replaced `Bunyan` with `Pino` as its default logger. This is a significant change, requiring updates to logging configuration and potentially replacing `restify-bunyan-logger` with `restify-pino-logger` or a similar integration. Also, `RequestCaptureStream` was removed.
- breaking The behavior of `next()` with a string parameter for re-routing was deprecated and subsequently removed. `next('route-name')` will no longer re-route the request.
- breaking Support for Node.js 8 was dropped. This means applications running on Node.js 8 or older will no longer be compatible with Restify v9.0.0 and above.
- gotcha Restify extensively uses `next()` for middleware chaining. Forgetting to call `next()` or calling it incorrectly (e.g., passing a non-Error object in older versions when an error is intended) can halt the request processing or lead to unexpected behavior.
- gotcha Restify's DTrace support, while powerful for observability, relies on `dtrace-provider` which might cause issues during installation or compilation on systems without DTrace (e.g., Windows).
Install
-
npm install restify -
yarn add restify -
pnpm add restify
Imports
- createServer
import { createServer } from 'restify'; // createServer is not a named export from the top-level 'restify' module in all versionsimport * as restify from 'restify'; const server = restify.createServer({ name: 'MyApi' }); - plugins
import { plugins } from 'restify'; // `plugins` is not a direct named exportimport * as restify from 'restify'; server.use(restify.plugins.bodyParser());
- Request, Response, Next (TypeScript types)
import { Request, Response, Next } from 'restify'; - CommonJS require
import restify from 'restify'; // While technically possible with transpilation, direct ESM usage for the main module might differ in older versions.
const restify = require('restify'); const server = restify.createServer();
Quickstart
import * as restify from 'restify';
import { Request, Response, Next } from 'restify';
const server = restify.createServer({
name: 'MyRestifyApp',
version: '1.0.0'
});
// Apply common plugins
server.use(restify.plugins.bodyParser()); // Parses application/json, application/x-www-form-urlencoded, multipart/form-data
server.use(restify.plugins.queryParser()); // Parses URL query parameters into req.query
// Define a GET route with a parameter
server.get('/hello/:name', (req: Request, res: Response, next: Next) => {
res.send({
message: `Hello, ${req.params.name}!`, // Access route parameters
query: req.query,
// body: req.body // Body is not typically present for GET requests
});
return next(); // Pass control to the next handler in the chain
});
// Define a POST route to receive data
server.post('/data', (req: Request, res: Response, next: Next) => {
if (!req.body) {
res.send(400, { message: 'Request body is required.' });
return next(false); // Stop the chain if an error occurs
}
res.send(201, {
received: req.body, // Access parsed request body
status: 'Data processed successfully.'
});
return next();
});
// Event listener for unhandled routes (404 Not Found)
server.on('NotFound', (req: Request, res: Response, next: Next) => {
res.send(404, { message: 'The requested resource was not found.' });
return next();
});
// Global error handler for Restify errors
server.on('restifyError', (req: Request, res: Response, err: Error, callback: () => void) => {
console.error(`Unhandled Restify error for ${req.url}:`, err);
// Optionally modify the error response before sending
// err.toJSON = () => ({ error: { name: err.name, message: err.message, code: (err as any).statusCode } });
return callback(); // Continue the error handling chain
});
const port = process.env.PORT ?? 8080;
server.listen(port, () => {
console.log('%s listening at %s', server.name, server.url); // Server.url is populated after listen()
});