@hapi/hapi is a comprehensive HTTP server framework for Node.js that enables developers to build powerful, scalable web applications and APIs with minimal overhead and full out-of-the-box functionality. It offers a rich set of features including built-in authentication, input validation, caching, logging, error handling, and plugin architecture, with extensive support for routing, request/response lifecycle management, security features like CORS and CSRF protection, and performance optimizations.
npm install @hapi/hapiconst Hapi = require('@hapi/hapi');ESM (ES6 modules):
import Hapi from '@hapi/hapi';const Hapi = require('@hapi/hapi');
const init = async () => {
// Create server instance
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// Add a route
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'Hello World!';
}
});
// Start the server
await server.start();
console.log('Server running on %s', server.info.uri);
};
init();@hapi/hapi is built around several key components:
Core server creation, configuration, and lifecycle management. Essential for setting up and controlling HTTP servers.
function server(options?: ServerOptions): Server;
interface ServerOptions {
address?: string;
app?: object;
autoListen?: boolean;
cache?: CacheOptions | CacheOptions[];
compression?: CompressionOptions | false;
debug?: DebugOptions | false;
host?: string;
info?: { remote?: boolean };
listener?: object;
load?: LoadOptions;
mime?: MimeOptions;
operations?: OperationsOptions;
plugins?: object;
port?: number | string;
query?: QueryOptions;
router?: RouterOptions;
routes?: RouteOptions;
state?: StateOptions;
tls?: object | boolean;
uri?: string;
}Powerful routing system with pattern matching, parameter extraction, and route-specific configuration options.
interface RouteConfiguration {
method: string | string[];
path: string;
handler: RouteHandler | object;
options?: RouteOptions;
}
type RouteHandler = (request: Request, h: ResponseToolkit) => any;Rich request object with parsed headers, payload, query parameters, and extensive metadata for handling HTTP requests.
interface Request {
app: object;
auth: AuthInfo;
events: Events;
headers: { [key: string]: string };
info: RequestInfo;
method: string;
params: { [key: string]: string };
path: string;
payload: any;
query: { [key: string]: string };
response: Response;
route: RouteInfo;
server: Server;
state: { [key: string]: any };
}Comprehensive response object with methods for setting headers, status codes, content type, caching, and state management.
interface Response {
statusCode: number;
headers: { [key: string]: string };
source: any;
variety: string;
app: object;
plugins: object;
settings: ResponseSettings;
}Pluggable authentication system supporting multiple schemes and strategies with built-in session management.
interface AuthAPI {
scheme(name: string, scheme: AuthScheme): void;
strategy(name: string, scheme: string, options?: object): void;
default(options: AuthOptions): void;
test(name: string, request: Request): Promise<AuthTestResult>;
}Lifecycle hooks for intercepting and modifying request processing at various stages of the pipeline.
interface ExtensionPoint {
method: ExtensionMethod;
options?: ExtensionOptions;
}
type ExtensionMethod = (request: Request, h: ResponseToolkit) => any;
type ExtensionEvent = 'onRequest' | 'onPreAuth' | 'onCredentials' |
'onPostAuth' | 'onPreHandler' | 'onPostHandler' |
'onPreResponse' | 'onPostResponse';Modular plugin architecture for extending server functionality with dependency management and isolation.
interface PluginObject {
name: string;
version?: string;
register: PluginRegister;
requirements?: PluginRequirements;
dependencies?: string | string[];
once?: boolean;
}
type PluginRegister = (server: Server, options: object) => Promise<void> | void;Built-in caching system with support for multiple backends and policies for server methods and general purpose caching.
interface CacheAPI {
cache(options: CachePolicyOptions): CachePolicy;
provision(options: CacheProvisionOptions): Promise<void>;
}Input validation system with support for Joi and other validation libraries for request payload, query parameters, and headers.
interface ValidationOptions {
payload?: object;
query?: object;
params?: object;
headers?: object;
state?: object;
failAction?: ValidationFailAction;
options?: object;
}Server event system providing lifecycle hooks and logging capabilities.
interface Events {
on(event: string, listener: Function): void;
once(event: string, listener: Function): void;
emit(event: string, ...args: any[]): boolean;
removeListener(event: string, listener: Function): void;
}
type ServerEvent = 'log' | 'start' | 'stop' | 'closing' | 'route' | 'cachePolicy' | 'request' | 'response';Server Events:
'log''start''stop''closing''route''cachePolicy''request''response'Usage Examples:
const server = Hapi.server({ port: 3000 });
// Listen to server events
server.events.on('log', (event, tags) => {
if (tags.error) {
console.error('Server error:', event.error);
} else if (tags.info) {
console.log('Server info:', event.data);
}
});
server.events.on('start', () => {
console.log('Server started at:', server.info.uri);
});
server.events.on('stop', () => {
console.log('Server stopped');
});
server.events.on('request', (request, event, tags) => {
if (tags.error) {
console.error(`Request ${request.info.id} error:`, event.error);
}
});
server.events.on('response', (request) => {
console.log(`${request.method.toUpperCase()} ${request.path} -> ${request.response.statusCode}`);
});interface Server {
// Properties
app: object;
auth: AuthAPI;
cache: CacheAPI;
decorations: Decorations;
events: Events;
info: ServerInfo;
listener: object;
load: LoadMetrics;
methods: object;
mime: MimeDatabase;
plugins: object;
registrations: object;
settings: ServerOptions;
states: StateManager;
type: string;
version: string;
realm: Realm;
// Methods
bind(context: object): void;
control(server: Server): void;
decorate(type: string, property: string, method: any, options?: object): void;
dependency(dependencies: string | string[], after?: Function): void;
encoder(encoding: string, encoder: Function): void;
decoder(encoding: string, decoder: Function): void;
event(event: object): void;
expose(key: string | object, value?: any, options?: object): void;
ext(events: string | string[] | ExtensionPoint[], method?: Function, options?: object): void;
initialize(): Promise<void>;
inject(options: string | InjectOptions): Promise<InjectResponse>;
log(tags: string | string[], data?: any): void;
lookup(id: string): RoutePublic | null;
match(method: string, path: string, host?: string): RoutePublic | null;
method(name: string | MethodObject[], method?: Function, options?: object): void;
path(relativeTo: string): void;
register(plugins: PluginObject | PluginObject[], options?: object): Promise<void>;
route(route: RouteConfiguration | RouteConfiguration[]): void;
rules(processor: Function, options?: object): void;
start(): Promise<void>;
state(name: string, options?: StateDefinitionOptions): void;
stop(options?: object): Promise<void>;
table(host?: string): RoutePublic[];
validator(validator: object): void;
}
interface ResponseToolkit {
abandon: symbol;
close: symbol;
continue: symbol;
context: object;
realm: Realm;
request: Request;
authenticated(data: AuthCredentials): object;
entity(options?: EntityOptions): ResponseObject | symbol;
redirect(uri?: string): ResponseObject;
response(value?: any): ResponseObject;
state(name: string, value: any, options?: StateUpdateOptions): void;
unauthenticated(error: Error, data?: AuthCredentials): object;
unstate(name: string, options?: StateUpdateOptions): void;
}
interface LoadMetrics {
/** Current event loop delay in milliseconds */
eventLoopDelay: number;
/** Current heap usage in bytes */
heapUsed: number;
/** Current RSS memory usage in bytes */
rss: number;
}
interface Decorations {
/** Server decorations */
server: Map<string, any>;
/** Request decorations */
request: Map<string, any>;
/** Response toolkit decorations */
toolkit: Map<string, any>;
}
interface MimeDatabase {
/** Get MIME type for file path */
path(path: string): MimeEntry;
/** Get MIME type for extension */
type(type: string): MimeEntry;
}
interface MimeEntry {
/** MIME type */
type: string;
/** Character set */
charset?: string;
/** Whether the type is compressible */
compressible: boolean;
}
interface StateManager {
/** Add state configuration */
add(name: string, options?: StateDefinitionOptions): void;
/** Format cookies for Set-Cookie header */
format(cookies: object): string;
/** Parse cookies from Cookie header */
parse(header: string): object;
/** State configurations */
settings: object;
/** Cookie definitions */
cookies: object;
/** Cookie names */
names: string[];
}
interface InjectOptions {
/** HTTP method */
method?: string;
/** Request URL */
url: string;
/** Request headers */
headers?: { [key: string]: string };
/** Request payload */
payload?: any;
/** Authentication credentials */
credentials?: object;
/** Inject into specific server */
authority?: string;
/** Whether to process as remote request */
remoteAddress?: string;
/** Simulate connection info */
simulate?: {
end?: boolean;
split?: boolean;
error?: boolean;
close?: boolean;
};
/** Request validation options */
validate?: boolean;
}
interface InjectResponse {
/** Response status code */
statusCode: number;
/** Response headers */
headers: { [key: string]: string };
/** Response payload */
payload: string;
/** Raw response payload */
rawPayload: Buffer;
/** Raw request object */
raw: {
req: object;
res: object;
};
/** Response result object */
result: any;
/** Request object */
request: Request;
}
interface MethodObject {
/** Method name */
name: string;
/** Method function */
method: Function;
/** Method options */
options?: object;
}
interface StateDefinitionOptions {
/** Cookie time-to-live in milliseconds */
ttl?: number;
/** Whether cookie is HTTP-only */
isHttpOnly?: boolean;
/** Whether cookie is secure */
isSecure?: boolean;
/** SameSite attribute */
isSameSite?: 'Strict' | 'Lax' | 'None' | false;
/** Cookie path */
path?: string;
/** Cookie domain */
domain?: string;
/** Cookie encoding type */
encoding?: 'none' | 'base64' | 'base64json' | 'form' | 'iron';
/** Iron password for encryption */
password?: string | object;
/** Default value */
clearInvalid?: boolean;
/** Ignore errors when parsing */
ignoreErrors?: boolean;
/** Whether cookie applies to same site */
strictHeader?: boolean;
/** Fail action for parsing errors */
failAction?: 'error' | 'log' | 'ignore';
/** Cookie signing options */
sign?: {
password: string | object;
integrity?: object;
};
}