### Define and Start Hapi Server with Routes Source: https://github.com/hapijs/hapi/wiki/Adding-routes This snippet shows how to create a Hapi server, define two GET routes (one for the root and one with a dynamic parameter), and start the server. Remember to URI encode user-provided data to prevent injection attacks. ```javascript var Hapi = require('hapi'); var server = new Hapi.Server(); server.connection({ port: 3000 }); server.route({ method: 'GET', path: '/', handler: function (request, reply) { reply('Hello, world!'); } }); server.route({ method: 'GET', path: '/{name}', handler: function (request, reply) { reply('Hello, ' + encodeURIComponent(request.params.name) + '!'); } }); server.start(function () { console.log('Server running at:', server.info.uri); }); ``` -------------------------------- ### Create a Basic Hapi.js Server Source: https://github.com/hapijs/hapi/wiki/Getting-Started This JavaScript code demonstrates how to create a Hapi server, define a simple GET route, and start the server. ```Javascript var hapi = require('hapi'); // Create a server with a host and port var server = new hapi.server({ host: 'localhost', port: 8000 }); // Add a route server.route({ method: 'GET', path: '/hello', handler: function (request, reply) { reply("Hello, World!"); } }); // Server the server server.start(); ``` -------------------------------- ### Install Hapi.js Source: https://github.com/hapijs/hapi/wiki/Getting-Started Install the Hapi.js framework and save it as a project dependency. ```Bash npm install hapi --save ``` -------------------------------- ### await server.start() Source: https://github.com/hapijs/hapi/blob/master/API.md Starts the Hapi server, making it ready to listen for incoming requests on the configured port. It's recommended to abort the process if the server fails to start. ```APIDOC ## `await server.start()` ### Description Starts the server by listening for incoming requests on the configured port (unless the connection was configured with `autoListen` set to `false`). ### Return Value None. ### Notes - If the method fails and throws an error, the server is considered to be in an undefined state and should be shut down. - If a started server is started again, the second call to `server.start()` is ignored. ``` -------------------------------- ### Start Hapi Server Source: https://github.com/hapijs/hapi/blob/master/API.md Starts the Hapi server and listens for incoming requests. If the server fails to start, it is recommended to shut down and reset the state before retrying. ```javascript const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); await server.start(); console.log('Server started at: ' + server.info.uri); } ``` -------------------------------- ### server.initialize() Source: https://github.com/hapijs/hapi/blob/master/API.md Initializes the server, starting caches and finalizing plugin registration, but does not start listening on the connection port. ```APIDOC ## await server.initialize() ### Description Initializes the server (starts the caches, finalizes plugin registration) but does not start listening on the connection port. ### Return Value none. ### Note If the method fails and throws an error, the server is considered to be in an undefined state and should be shut down. It is recommended to abort the process when the server fails to start properly. If you must try to resume after an error, call [`server.stop()`](#server.stop()) first to reset the server state. ### Request Example ```js const Hapi = require('@hapi/hapi'); const Hoek = require('@hapi/hoek'); async function example() { const server = Hapi.server({ port: 80 }); await server.initialize(); } ``` ``` -------------------------------- ### Listen for 'start' Event Source: https://github.com/hapijs/hapi/blob/master/API.md Emitted when the server is started using server.start(). The handler takes no arguments. ```javascript server.events.on('start', () => { console.log('Server started'); }); ``` -------------------------------- ### Initialize Server with server.initialize() Source: https://github.com/hapijs/hapi/blob/master/API.md Use `server.initialize()` to start caches and finalize plugin registration without starting connection listeners. If initialization fails, the server is in an undefined state and should be shut down. ```javascript const Hapi = require('@hapi/hapi'); const Hoek = require('@hapi/hoek'); async function example() { const server = Hapi.server({ port: 80 }); await server.initialize(); } ``` -------------------------------- ### Server Start Event Source: https://github.com/hapijs/hapi/blob/master/API.md Emitted when the server is started using server.start(). The handler takes no arguments. ```APIDOC ## 'start' Event ### Description Emitted when the server is started using `server.start()`. The handler takes no arguments. ### Signature `function()` ### Example ```javascript server.events.on('start', () => { console.log('Server started'); }); ``` ``` -------------------------------- ### Define a GET Route with Optional Parameter Source: https://github.com/hapijs/hapi/wiki/Routes This example demonstrates defining a GET route with an optional path parameter. The handler function constructs a greeting message, defaulting to 'stranger' if the user parameter is not provided. The config object includes metadata like description, notes, and tags, which can be used by plugins for documentation. ```Javascript server.route({ method: 'GET', path: '/hello/{user?}', handler: function (request, reply) { var user = request.params.user ? encodeURIComponent(request.params.user) : 'stranger'; reply('Hello ' + request.params.user + '!'); }, config: { description: 'Say hello!', notes: 'The user parameter defaults to \'stranger\' if unspecified', tags: ['api', 'greeting'] } }); ``` -------------------------------- ### Create Basic Hapi Server Source: https://github.com/hapijs/hapi/wiki/Creating-a-server Use this snippet to create a simple Hapi server listening on a specified port. Ensure you have installed Hapi using 'npm install hapi --save'. ```javascript var Hapi = require('hapi'); // Require the hapi module whence you have ran the "npm install hapi --save" command var server = new Hapi.Server(); // Create a server object server.connection({ port: 3000 }); // Add connection. Here we added the port number // Start the server server.start(function () { console.log('Server running at:', server.info.uri); }); ``` -------------------------------- ### Install Hapi Logging Plugins Source: https://github.com/hapijs/hapi/wiki/Using-plugins Install the 'good' and 'good-console' npm packages to add basic logging functionality to your Hapi application. ```bash npm install good --save npm install good-console --save ``` -------------------------------- ### Listening to 'request' events Source: https://github.com/hapijs/hapi/blob/master/API.md This example demonstrates how to listen for the 'request' event and log error details when they occur. ```APIDOC ## Listening to 'request' events ### Description This example demonstrates how to listen for the 'request' event and log error details when they occur. ### Method `server.events.on('request', (request, event, tags) => { ... });` ### Parameters - `request`: The request object. - `event`: An object containing event details: - `timestamp` (number): The event timestamp. - `tags` (array): An array of tags identifying the event (e.g., `['error', 'http']`). - `channel` (string): The event channel ('app', 'error', or 'internal'). - `request` (string): The request identifier. - `data` (any): Event-specific information (if not an error). - `error` (Error): The error object related to the event (if applicable). - `tags` (object): An object where each event tag is a key with a value of `true`. ### Request Example ```js server.events.on('request', (request, event, tags) => { if (tags.error) { console.log(`Request ${event.request} error: ${event.error ? event.error.message : 'unknown'}`); } }); ``` ``` -------------------------------- ### Quick Start with TypeScript in Hapi Source: https://github.com/hapijs/hapi/blob/master/typescript.md Demonstrates setting up a Hapi server with TypeScript, defining application state, and configuring a route with per-route parameter typing. Use `createServer()` to type `server.app` and route generics like `{ Params: { id: string } }` to override default parameter types for specific routes. ```typescript import { server as createServer, ServerRoute, Request, ResponseToolkit } from '@hapi/hapi'; interface AppSpace { startedAt: number; } const server = createServer({ port: 3000 }); server.app.startedAt = Date.now(); const route: ServerRoute<{ Params: { id: string } }> = { method: 'GET', path: '/users/{id}', handler: (request, h) => { const id: string = request.params.id; return { id }; } }; server.route(route); ``` -------------------------------- ### server.state() Source: https://github.com/hapijs/hapi/blob/master/API.md This example demonstrates how to listen for internal server events, specifically filtering for 'error' and 'state' tags to log state-related errors. ```APIDOC ## `server.state(name, [options])` ### Description This method is used to register a state definition with the server. It allows you to define how cookies are managed, including encryption and signing. ### Method `server.state(name, [options])` ### Parameters - **name** (string) - Required - The name of the state. - **options** (object) - Optional - Configuration options for the state. - **password** (string) - Required - The password used for encryption and signing. - **isSecure** (boolean) - Optional - If true, the cookie will only be sent over HTTPS. - **isHttpOnly** (boolean) - Optional - If true, the cookie will not be accessible via client-side JavaScript. - **isSameSite** (string) - Optional - Controls the SameSite attribute for the cookie. Can be 'Strict', 'Lax', or 'None'. - **path** (string) - Optional - The path for which the cookie is valid. - **domain** (string) - Optional - The domain for which the cookie is valid. - **ttl** (number) - Optional - The time-to-live for the cookie in milliseconds. ### Example ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); server.state('session', { password: 'cookie-password', isSecure: process.env.NODE_ENV === 'production' }); // ... server routes and other configurations await server.start(); ``` ### Event Handling Example This example demonstrates how to listen for internal server events, specifically filtering for 'error' and 'state' tags to log state-related errors. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); server.events.on({ name: 'request', channels: 'internal' }, (request, event, tags) => { if (tags.error && tags.state) { console.error(event); } }); ``` ``` -------------------------------- ### Define a Basic GET Route Source: https://github.com/hapijs/hapi/wiki/Routes This snippet shows the fundamental structure for defining a GET route with a simple handler that replies with 'Hello!'. ```javascript server.route({ method: 'GET', path: '/', handler: function (request, reply) { reply('Hello!'); } }); ``` -------------------------------- ### Configuring Route-Level Extension Points Source: https://github.com/hapijs/hapi/blob/master/typescript.md Implement route-level extension points using the `ext` option. This example shows how to use the `onPreHandler` extension point to log information before the main handler is executed. ```typescript const route: ServerRoute = { method: 'GET', path: '/', options: { ext: { onPreHandler: { method: (request, h) => { request.log(['info'], 'pre-handler'); return h.continue; } } }, handler: (request, h) => 'ok' } }; ``` -------------------------------- ### Handle Request Events with Hapi Source: https://github.com/hapijs/hapi/blob/master/API.md This example shows how to use request events like 'peek', 'finish', and 'disconnect' to process payload data and handle request completion or abortion. It requires the 'crypto' and '@hapi/hapi' modules. ```javascript const Crypto = require('crypto'); const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); const onRequest = function (request, h) { const hash = Crypto.createHash('sha1'); request.events.on('peek', (chunk) => { hash.update(chunk); }); request.events.once('finish', () => { console.log(hash.digest('hex')); }); request.events.once('disconnect', () => { console.error('request aborted'); }); return h.continue; }; server.ext('onRequest', onRequest); ``` -------------------------------- ### server.control(server) Source: https://github.com/hapijs/hapi/blob/master/API.md Links another server to the initialize/start/stop state of the current server. The controlled server's initialize(), start(), and stop() methods are called whenever the current server's corresponding methods are called. ```APIDOC ## server.control(server) ### Description Links another server to the initialize/start/stop state of the current server. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **server** (object) - Required - the **hapi** server object to be controlled. ### Request Example None provided. ### Response #### Success Response (200) None provided. #### Response Example None provided. ``` -------------------------------- ### Register Request Extension with server.ext(events) Source: https://github.com/hapijs/hapi/blob/master/API.md Use `server.ext()` with an object to register extension functions for request lifecycle events like 'onRequest'. Ensure the method signature matches the extension point. This example redirects all requests to '/test'. ```javascript const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); server.ext({ type: 'onRequest', method: function (request, h) { // Change all requests to '/test' request.setUrl('/test'); return h.continue; } }); server.route({ method: 'GET', path: '/test', handler: () => 'ok' }); await server.start(); // All requests will get routed to '/test' } ``` -------------------------------- ### Define a Route with a Named Path Parameter Source: https://github.com/hapijs/hapi/wiki/Routes This example demonstrates how to define a route with a named parameter in the path (e.g., '/hello/{user}'). The parameter's value is accessible within the handler via `request.params.user` and should be URI encoded to prevent injection attacks. ```javascript server.route({ method: 'GET', path: '/hello/{user}', handler: function (request, reply) { reply('Hello ' + encodeURIComponent(request.params.user) + '!'); } }); ``` -------------------------------- ### server.dependency() Source: https://github.com/hapijs/hapi/blob/master/API.md Declares a plugin's dependency on other plugins, ensuring they are registered before the server starts. Supports specifying version ranges and an optional callback function to execute after dependencies are met. ```APIDOC ## server.dependency(dependencies, [after]) ### Description Used within a plugin to declare a required dependency on other plugins. The specified plugins must be registered before the server is initialized or started. ### Parameters - `dependencies` - (string | string[] | object) - One or more plugin names, or an object mapping plugin names to version range strings. - `after` - (function, optional) - A function called after all dependencies are registered and before the server starts. Signature: `async function(server)`. ### Return Value None. ### Example ```js const after = function (server) { // Additional plugin registration logic }; exports.plugin = { name: 'example', register: function (server, options) { server.dependency('yar', after); } }; ``` ### Alternative Configuration Dependencies can also be set via the plugin `dependencies` property: ```js exports.plugin = { name: 'test', version: '1.0.0', dependencies: { yar: '1.x.x' }, register: function (server, options) { } }; ``` ``` -------------------------------- ### Get Hapi Server Version Source: https://github.com/hapijs/hapi/blob/master/API.md Retrieve the installed version number of the Hapi module. This is a read-only property. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server(); console.log(server.version); // '17.0.0' ``` -------------------------------- ### Initialize npm Project Source: https://github.com/hapijs/hapi/wiki/Getting-Started Use this command to create a package.json file for your project. ```Bash npm init ``` -------------------------------- ### Change Request Method with request.setMethod() Source: https://github.com/hapijs/hapi/blob/master/API.md Modify the request method before routing using request.setMethod(method). This can only be called from an 'onRequest' extension method. Example changes all requests to 'GET'. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); const onRequest = function (request, h) { // Change all requests to 'GET' request.setMethod('GET'); return h.continue; }; server.ext('onRequest', onRequest); ``` -------------------------------- ### Decoration Options Source: https://github.com/hapijs/hapi/blob/master/typescript.md Explains the 'apply' and 'extend' options available when using `server.decorate()`, detailing their purpose and limitations. ```APIDOC ### Options - `apply` — when `type` is `'request'`, if `true`, the function is called with the request object and the return value becomes the decoration. Useful for computed properties. - `extend` — if `true`, overrides an existing decoration. The function receives the previous value and must return the new one. Cannot be used with `'handler'`. ``` -------------------------------- ### Route Configuration - Extension Points Source: https://github.com/hapijs/hapi/blob/master/typescript.md Illustrates how to configure route-level extension points using the `ext` option, such as `onPreHandler`. ```APIDOC ### Extension Points Route-level extension points use the `ext` option: ```typescript const route: ServerRoute = { method: 'GET', path: '/', options: { ext: { onPreHandler: { method: (request, h) => { request.log(['info'], 'pre-handler'); return h.continue; } } }, handler: (request, h) => 'ok' } }; ``` ``` -------------------------------- ### Bridging Example with Generic Request Function (TypeScript) Source: https://github.com/hapijs/hapi/blob/master/typescript.md Shows a practical example of a generic function `extractToken` that works with any `Request` object, regardless of its specific refs. This function is then used within a route handler. ```typescript import { ReqRef, Request } from '@hapi/hapi'; // Generic: accepts Request with any refs function extractToken(req: Request): string | undefined { const auth = req.headers['authorization']; if (typeof auth === 'string') { return auth.replace('Bearer ', ''); } return undefined; } // Works with any route's request const route: ServerRoute<{ Params: { id: string } }> = { method: 'GET', path: '/users/{id}', handler: (request, h) => { const token = extractToken(request); // works return { id: request.params.id, token }; } }; ``` -------------------------------- ### Decorations - Step 2: Register Decorations Source: https://github.com/hapijs/hapi/blob/master/typescript.md This step shows the actual registration of decorations for 'request', 'toolkit', and 'server' targets using `server.decorate()`. ```APIDOC ### Step 2: Register Decorations ```typescript // Request decoration server.decorate('request', 'getIp', function (this: Request) { return this.info.remoteAddress; }); // Toolkit decoration server.decorate('toolkit', 'success', function (this: ResponseToolkit, data: object) { return this.response(data).code(200); }); // Server decoration server.decorate('server', 'getUptime', function (this: Server) { return Date.now() - this.info.started; }); ``` ``` -------------------------------- ### response.rewritable() Source: https://github.com/hapijs/hapi/blob/master/API.md Sets whether the redirect is rewritable (POST to GET) or non-rewritable. ```APIDOC ## response.rewritable(isRewritable) ### Description Sets the status code to `301`/`302` for rewritable (allows changing the request method from 'POST' to 'GET') or `307`/`308` for non-rewritable (does not allow changing the request method from 'POST' to 'GET'). The exact code depends on the [`response.temporary()`](#response.temporary()) or [`response.permanent()`](#response.permanent()) setting. If `isRewritable` is `false`, sets to non-rewritable. Defaults to `true`. ### Parameters #### Path Parameters - **isRewritable** (boolean) - Optional - If `false`, sets to non-rewritable. Defaults to `true`. ### Notes Only available after calling the [`response.redirect()`](#response.redirect()) method. ``` -------------------------------- ### Registering Server Methods Source: https://github.com/hapijs/hapi/wiki/Server-methods Demonstrates two ways to register a server method: passing individual parameters or an object. The method function must accept a callback as its last argument. ```javascript var add = function (x, y, next) { next(null, x + y); // You must use the next callback to return values } // Method 1: Passing separate parameters server.method('add', add, {}); // Method 2: Adding an object instead server.method({ name: 'add', method: add, options: {} }); ``` -------------------------------- ### Access Server Port Information Source: https://github.com/hapijs/hapi/blob/master/API.md Access read-only server information, specifically the configured port before the server starts. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); console.log(server.info.port); // 80 ``` -------------------------------- ### Listening to specific 'request' channels Source: https://github.com/hapijs/hapi/blob/master/API.md This example shows how to filter 'request' events to listen only to a specific channel, such as 'error'. ```APIDOC ## Listening to specific 'request' channels ### Description This example shows how to filter 'request' events to listen only to a specific channel, such as 'error'. ### Method `server.events.on({ name: 'request', channels: 'error' }, (request, event, tags) => { ... });` ### Parameters - `request`: The request object. - `event`: An object containing event details. - `tags` (object): An object where each event tag is a key with a value of `true`. ### Request Example ```js server.events.on({ name: 'request', channels: 'error' }, (request, event, tags) => { console.log(`Request ${event.request} failed`); }); ``` ``` -------------------------------- ### Registering a Method Source: https://github.com/hapijs/hapi/blob/master/typescript.md Demonstrates how to register a server method with optional caching and key generation. Nested names automatically create object hierarchies. ```APIDOC ## Registering a Method ```typescript server.method('utils.add', (a: number, b: number) => a + b, { cache: { expiresIn: 60000, generateTimeout: 100 }, generateKey: (a: number, b: number) => `${a}:${b}` }); ``` Nested names (e.g. `'utils.add'`) automatically create the object hierarchy under `server.methods`. ``` -------------------------------- ### Route Cache Options Source: https://github.com/hapijs/hapi/blob/master/API.md Configures HTTP caching for GET routes, allowing customization of cache privacy, expiration, and status codes. ```APIDOC ## route.options.cache Default value: `{ privacy: 'default', statuses: [200], otherwise: 'no-cache' }`. If the route method is 'GET', the route can be configured to include HTTP caching directives in the response. Caching can be customized using an object with the following options: - `privacy` - determines the privacy flag included in client-side caching using the 'Cache-Control' header. Values are: - `'default'` - no privacy flag. - `'public'` - mark the response as suitable for public caching. - `'private'` - mark the response as suitable only for private caching. - `expiresIn` - relative expiration expressed in the number of milliseconds since the item was saved in the cache. Cannot be used together with `expiresAt`. - `expiresAt` - time of day expressed in 24h notation using the 'HH:MM' format, at which point all cache records for the route expire. Cannot be used together with `expiresIn`. - `statuses` - an array of HTTP response status code numbers (e.g. `200`) which are allowed to include a valid caching directive. - `otherwise` - a string with the value of the 'Cache-Control' header when caching is disabled. The default `Cache-Control: no-cache` header can be disabled by setting `cache` to `false`. ``` -------------------------------- ### Route Configuration - RouteApp Source: https://github.com/hapijs/hapi/blob/master/typescript.md Demonstrates how to type the `options.app` property on routes for custom route-specific application data. ```APIDOC ## Route Configuration ### RouteApp Type the `options.app` property on routes: ```typescript interface AdminRefs { RouteApp: { requiredRole: string }; } const route: ServerRoute = { method: 'GET', path: '/admin', options: { app: { requiredRole: 'admin' }, handler: (request, h) => { const role: string = request.route.settings.app!.requiredRole; return { role }; } } }; ``` ``` -------------------------------- ### Get Hapi Server Routing Table Source: https://github.com/hapijs/hapi/blob/master/API.md Retrieves a copy of the server's routing table. Can be filtered by a specific virtual host. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); server.route({ method: 'GET', path: '/example', handler: () => 'ok' }); const table = server.table(); ``` -------------------------------- ### Typing Query Parameters with an Interface Source: https://github.com/hapijs/hapi/blob/master/typescript.md Define a specific interface for query parameters to ensure type safety. This example demonstrates typing query parameters for a search route. ```typescript interface SearchQuery { q: string; page?: string; tags?: string[]; } const route: ServerRoute<{ Query: SearchQuery }> = { method: 'GET', path: '/search', handler: (request, h) => { const q: string = request.query.q; const page: string | undefined = request.query.page; return { q, page }; } }; ``` -------------------------------- ### server.ext(event, [method, [options]]) Source: https://github.com/hapijs/hapi/blob/master/API.md Registers a single extension event using properties passed as arguments. This is a shorthand for the `server.ext(events)` method. ```APIDOC ## server.ext(event, [method, [options]]) ### Description Registers a single extension event using the same properties as used in [`server.ext(events)`](#server.ext()), but passed as arguments. ### Parameters - `event` - the extension point event name. - `method` - (optional) a function or an array of functions to be executed. - `options` - (optional) an object with configuration options for the extension. ### Return Value A promise if `method` is omitted, otherwise `undefined`. ### Request Example ```js const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); server.ext('onRequest', function (request, h) { // Change all requests to '/test' request.setUrl('/test'); return h.continue; }); server.route({ method: 'GET', path: '/test', handler: () => 'ok' }); await server.start(); // All requests will get routed to '/test' } ``` ``` -------------------------------- ### Hapi Bind Ref Key Example (TypeScript) Source: https://github.com/hapijs/hapi/blob/master/typescript.md Demonstrates how to use the `Bind` ref key to control the `this` binding in lifecycle methods. Note that `this` binding is ignored for arrow functions. ```typescript interface MyContext { greeting: string; } interface MyRefs { Bind: MyContext; } const route: ServerRoute = { method: 'GET', path: '/', options: { bind: { greeting: 'Hello' }, handler: function (request, h) { return this.greeting; // typed as MyContext } } }; ``` -------------------------------- ### Route Configuration - Rules Source: https://github.com/hapijs/hapi/blob/master/typescript.md Shows how to type custom route rules using the `Rules` ref key. ```APIDOC ### Rules Type custom route rules via the `Rules` ref key: ```typescript interface MyRules { mapTo: string; } interface MyRefs { Rules: MyRules; } const route: ServerRoute = { method: 'GET', path: '/mapped', rules: { mapTo: '/other' }, handler: (request, h) => 'ok' }; ``` ``` -------------------------------- ### Handle Response Events with Hapi Source: https://github.com/hapijs/hapi/blob/master/API.md Use response events 'peek' and 'finish' to process data chunks as they are written and when the response is complete. This example calculates a SHA1 hash of the response body. ```javascript const Crypto = require('crypto'); const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); const preResponse = function (request, h) { const response = request.response; if (response.isBoom) { return null; } const hash = Crypto.createHash('sha1'); response.events.on('peek', (chunk) => { hash.update(chunk); }); response.events.once('finish', () => { console.log(hash.digest('hex')); }); return h.continue; }; server.ext('onPreResponse', preResponse); ``` -------------------------------- ### Match Route by Method and Path Source: https://github.com/hapijs/hapi/blob/master/API.md Use server.match() to find a route configuration that matches a given HTTP method and path. An optional host argument can be provided to match routes with specific vhosts. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server(); server.route({ method: 'GET', path: '/', options: { id: 'root', handler: () => 'ok' } }); const route = server.match('get', '/'); ``` -------------------------------- ### Provision a Named Server Cache Source: https://github.com/hapijs/hapi/blob/master/API.md Provisions a named cache for the server, allowing it to be referenced by name. This is useful for managing multiple distinct cache configurations. Ensure the cache provider is installed and required. ```javascript const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); await server.initialize(); await server.cache.provision({ provider: require('@hapi/catbox-memory'), name: 'countries' }); const cache = server.cache({ cache: 'countries', expiresIn: 60 * 60 * 1000 }); await cache.set('norway', { capital: 'oslo' }); const value = await cache.get('norway'); } ``` -------------------------------- ### Create Hapi Server Source: https://github.com/hapijs/hapi/blob/master/API.md Instantiate a new Hapi server object. Options can be provided for server configuration. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ load: { sampleInterval: 1000 } }); ``` -------------------------------- ### Typing Request Properties with Custom Interfaces Source: https://github.com/hapijs/hapi/blob/master/typescript.md Define custom interfaces for route parameters and query strings to achieve strong typing. This example shows how to override default types for Params and Query. ```typescript interface MyRefs { Params: { id: string }; Query: { expand?: string }; } // MergeRefs resolves to: // { // Params: { id: string }; ← overridden // Query: { expand?: string }; ← overridden // Payload: stream.Readable | ...; ← default preserved // Headers: Record; ← default preserved // ...all other defaults preserved // } const route: ServerRoute = { method: 'GET', path: '/items/{id}', handler: (request, h) => { const id: string = request.params.id; // typed const expand: string | undefined = request.query.expand; // typed return { id }; } }; ``` -------------------------------- ### Declare Plugin Dependencies with server.dependency() Source: https://github.com/hapijs/hapi/blob/master/API.md Use server.dependency() within a plugin to specify required dependencies. The optional 'after' function executes after dependencies are registered and before the server starts. Circular dependencies will throw an error. ```javascript const after = function (server) { // Additional plugin registration logic }; exports.plugin = { name: 'example', register: function (server, options) { server.dependency('yar', after); } }; ``` ```javascript exports.plugin = { name: 'test', version: '1.0.0', dependencies: { yar: '1.x.x' }, register: function (server, options) { } }; ``` -------------------------------- ### Define a Catch-All Route for 404 Errors Source: https://github.com/hapijs/hapi/blob/master/API.md Implement a catch-all route with path '/{p*}' and a handler that returns a custom 404 response. This route should be defined last to ensure it only matches unhandled requests. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); const handler = function (request, h) { return h.response('The page was not found').code(404); }; server.route({ method: '*', path: '/{p*}', handler }); ``` -------------------------------- ### Register a Server Method with Simple Arguments Source: https://github.com/hapijs/hapi/blob/master/API.md Registers a server method for simple arguments with caching enabled. Ensure the Hapi module is required. ```javascript const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); const add = (a, b) => (a + b); server.method('sum', add, { cache: { expiresIn: 2000, generateTimeout: 100 } }); console.log(await server.methods.sum(4, 5)); // 9 } ``` -------------------------------- ### Register and Use Server Methods Source: https://github.com/hapijs/hapi/blob/master/API.md Register a utility function as a server method for reuse across the application. Access registered methods via `server.methods`. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server(); server.method('add', (a, b) => (a + b)); const result = server.methods.add(1, 2); // 3 ``` -------------------------------- ### server.match() Source: https://github.com/hapijs/hapi/blob/master/API.md Looks up a route configuration based on HTTP method and path. ```APIDOC ## server.match(method, path, [host]) ### Description Looks up a route configuration. ### Parameters #### method - (string) - The HTTP method (e.g. 'GET', 'POST'). #### path - (string) - The requested path (must begin with '/'). #### host - (string) - Optional - Hostname (to match against routes with `vhost`). ### Return Value - (object) - The [route information](#request.route) if found, otherwise `null`. ### Example ```js const Hapi = require('@hapi/hapi'); const server = Hapi.server(); server.route({ method: 'GET', path: '/', options: { id: 'root', handler: () => 'ok' } }); const route = server.match('get', '/'); ``` ``` -------------------------------- ### Hapi Request Handler Example Source: https://github.com/hapijs/hapi/blob/master/API.md A basic handler function that checks for a 'forbidden' query parameter and throws a Boom error if present, otherwise returns 'success'. Lifecycle methods can throw errors or return values. ```javascript const handler = function (request, h) { if (request.query.forbidden) { throw Boom.badRequest(); } return 'success'; }; ``` -------------------------------- ### Strict Pre-Handler Typing with Explicit Refs (TypeScript) Source: https://github.com/hapijs/hapi/blob/master/typescript.md Example of defining strict `Pres` refs for pre-handlers. By providing an explicit `Pres` key in the `StrictRefs` interface, you ensure strict typing for `request.pre` access, avoiding broad `any` type leakage. ```typescript interface StrictRefs { Pres: { user: UserObject; permissions: string[] }; } ``` -------------------------------- ### Route Configuration - Pre-handlers with Pres Source: https://github.com/hapijs/hapi/blob/master/typescript.md Explains how to type the `request.pre` object using `Pres` for pre-handlers and how their results are assigned. ```APIDOC ### Pre-handlers with `Pres` The `Pres` key types the `request.pre` object. Pre-handler results are assigned via the `assign` property. ```typescript interface MyRefs { Params: { id: string }; Pres: { user: { name: string; email: string } }; } const route: ServerRoute = { method: 'GET', path: '/users/{id}', options: { pre: [ { method: async (request, h) => { return { name: 'Test', email: 'test@example.com' }; }, assign: 'user' } ], handler: (request, h) => { const userName: string = request.pre.user.name; return { userName }; } } }; ``` ``` -------------------------------- ### server.register() Source: https://github.com/hapijs/hapi/blob/master/API.md Registers one or more plugins with the Hapi server. Plugins can be registered with options, and registration options like 'once' and 'routes' can be specified. ```APIDOC ## `await server.register(plugins, [options])` Registers a plugin where: - `plugins` - one or an array of: - a [plugin object](#plugins). - an object with the following: - `plugin` - a [plugin object](#plugins). - `options` - (optional) options passed to the plugin during registration. - `once`, `routes` - (optional) plugin-specific registration options as defined below. - `options` - (optional) registration options (different from the options passed to the registration function): - `once` - if `true`, subsequent registrations of the same plugin are skipped without error. Cannot be used with plugin options. Defaults to `false`. If not set to `true`, an error will be thrown the second time a plugin is registered on the server. - `routes` - modifiers applied to each route added by the plugin: - `prefix` - string added as prefix to any route path (must begin with `'/'`). If a plugin registers a child plugin the `prefix` is passed on to the child or is added in front of the child-specific prefix. - `vhost` - virtual host string (or array of strings) applied to every route. The outer-most `vhost` overrides the any nested configuration. Return value: a reference to the `server`. ```js async function example() { await server.register({ plugin: require('plugin_name'), options: { message: 'hello' } }); } ``` ``` -------------------------------- ### Register a Plugin with Options Source: https://github.com/hapijs/hapi/blob/master/API.md Registers a plugin with specific options. Ensure the plugin is correctly imported and the options match the plugin's expected configuration. ```javascript async function example() { await server.register({ plugin: require('plugin_name'), options: { message: 'hello' } }); } ``` -------------------------------- ### Define Pre-handler Methods for Route Source: https://github.com/hapijs/hapi/blob/master/API.md Use the 'pre' option to define methods that execute before the route handler. Methods can be run serially or in parallel, and their results can be assigned to request.pre for use in subsequent handlers or other pre-handlers. This example demonstrates parallel execution of two methods and a third method that combines their results. ```javascript const Hapi = require('@hapi/hapi'); const server = Hapi.server({ port: 80 }); const pre1 = function (request, h) { return 'Hello'; }; const pre2 = function (request, h) { return 'World'; }; const pre3 = function (request, h) { return request.pre.m1 + ' ' + request.pre.m2; }; server.route({ method: 'GET', path: '/', options: { pre: [ [ // m1 and m2 executed in parallel { method: pre1, assign: 'm1' }, { method: pre2, assign: 'm2' } ], { method: pre3, assign: 'm3' }, ], handler: function (request, h) { return request.pre.m3 + '!\n'; } } }); ``` -------------------------------- ### Server Creation Source: https://github.com/hapijs/hapi/blob/master/API.md Creates a new server object. The server manages all incoming requests along with all the facilities provided by the framework. Each server supports a single connection (e.g. listen to port 80). ```APIDOC ## `server([options])` Creates a new server object where: - `options` - (optional) a [server configuration object](#server.options). ```js const Hapi = require('@hapi/hapi'); const server = Hapi.server({ load: { sampleInterval: 1000 } }); ``` ``` -------------------------------- ### server.expose(key, value, [options]) Source: https://github.com/hapijs/hapi/blob/master/API.md Exposes a property from a plugin. The `key` and `value` are assigned to `server.plugins[name]`. Options control how plugin scopes are handled. ```APIDOC ## server.expose(key, value, [options]) ### Description Used within a plugin to expose a property via [`server.plugins[name]`](#server.plugins) where: - `key` - the key assigned ([`server.plugins[name][key]`](#server.plugins)). - `value` - the value assigned. - `options` - optional settings: - `scope` - controls how to handle the presence of a plugin scope in the name (e.g. `@hapi/test`): - `false` - the scope is removed (e.g. `@hapi/test` is changed to `test` under `server.plugins`). This is the default. - `true` - the scope is retained as-is (e.g. `@hapi/test` is used as `server.plugins['@hapi/test']`). - `'underscore'` - the scope is rewritten (e.g. `@hapi/test` is used as `server.plugins.hapi__test`). ### Return value none. ### Example ```javascript exports.plugin = name: 'example', register: function (server, options) { server.expose('util', () => console.log('something')); } }; ``` ``` -------------------------------- ### server.method(methods) Source: https://github.com/hapijs/hapi/blob/master/API.md Registers multiple server methods using an object or an array of method configurations. ```APIDOC ## `server.method(methods)` ### Description Registers multiple server method functions using a configuration object or an array of objects. ### Parameters #### `methods` (object | array) - An object or an array where each element contains: - `name` (string): The method name. - `method` (function): The method function. - `options` (object, optional): Settings for the method, same as in `server.method(name, method, [options])`. ### Return Value - none ### Example ```javascript const add = function (a, b) { return a + b; }; server.method({ name: 'sum', method: add, options: { cache: { expiresIn: 2000, generateTimeout: 100 } } }); ``` ``` -------------------------------- ### server.method(name, method, [options]) Source: https://github.com/hapijs/hapi/blob/master/API.md Registers a single server method. The method can be invoked later via `server.methods[name]`. Options include binding context and caching configurations. ```APIDOC ## `server.method(name, method, [options])` ### Description Registers a server method where `name` is a unique method name, `method` is the function to register, and `options` is an optional configuration object. ### Parameters #### `name` (string) - A unique method name used to invoke the method via `server.methods[name]`. #### `method` (function) - The method function with a signature `async function(...args, [flags])`. - `...args`: The method function arguments. - `flags`: An object provided automatically when caching is enabled, used to set optional method result flags (e.g., `ttl`). #### `options` (object, optional) - `bind` (object): A context object passed to the method function via `this`. Defaults to the active context. - `cache` (object): Cache configuration object. `generateTimeout` is required, `generateFunc` is not allowed. - `generateKey` (function): A function to generate a unique cache key from the method arguments. Required if arguments are not strings, numbers, or booleans. ### Return Value - none ### Examples #### Simple arguments example: ```javascript const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); const add = (a, b) => (a + b); server.method('sum', add, { cache: { expiresIn: 2000, generateTimeout: 100 } }); console.log(await server.methods.sum(4, 5)); // 9 } ``` #### Object argument example: ```javascript const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); const addArray = function (array) { let sum = 0; array.forEach((item) => { sum += item; }); return sum; }; const options = { cache: { expiresIn: 2000, generateTimeout: 100 }, generateKey: (array) => array.join(',') }; server.method('sumObj', addArray, options); console.log(await server.methods.sumObj([5, 6])); // 11 } ``` ``` -------------------------------- ### Register Extension with server.ext(event, method, options) Source: https://github.com/hapijs/hapi/blob/master/API.md Register a single extension event using arguments for type, method, and options. This is an alternative to the object-based approach and can be used to return a promise for testing purposes if the method is omitted. ```javascript const Hapi = require('@hapi/hapi'); async function example() { const server = Hapi.server({ port: 80 }); server.ext('onRequest', function (request, h) { // Change all requests to '/test' request.setUrl('/test'); return h.continue; }); server.route({ method: 'GET', path: '/test', handler: () => 'ok' }); await server.start(); // All requests will get routed to '/test' } ``` -------------------------------- ### Configure Server MIME Types Source: https://github.com/hapijs/hapi/blob/master/API.md Customize MIME type definitions for the server using the `mime` option during server initialization. Access the MIME database via `server.mime`. ```javascript const Hapi = require('@hapi/hapi'); const options = { mime: { override: { 'node/module': { source: 'steve', compressible: false, extensions: ['node', 'module', 'npm'], type: 'node/module' } } } }; const server = Hapi.server(options); console.log(server.mime.path('code.js').type) // 'application/javascript' console.log(server.mime.path('file.npm').type) // 'node/module' ```