Using hapi as the framework of choice for building web apps or APIs brings a lot built-in functionality to leverage from. In the end of August 2015 we published a post describing how to run separate frontend and backend servers within one project using hapi.
The mentioned post in the previous sentence shows you how to define and use different hapi server connections to separate the plugins and routes of front- and backend.
This article shows you how to use hapi’s server labels to select specific connections for further manipulation.
hapi Series Overview
- What You’ll Build
- Prepare Your Project: Stack & Structure
- Environment Variables and Storing Secrets
- Set Up MongoDB and Connect With Mongoose
- Sending Emails in Node.js
- Load the User’s Profile Picture From Gravatar Using Virtuals in Mongoose
- Implement a User Profile Editing Screen
- Generate a Username in Mongoose Middleware
- Displaying Seasons and Episodes for TV Shows with Mongoose Relationship Population
- Implementing Pagination for Movies
- Implement a Watchlist
- Create a Full Text Search with MongoDB
- Create a REST API with JSON Endpoints
- Update Mongoose Models for JSON Responses
- API Pagination for TV Shows
- Customize API Endpoints with Query Parameters
- Always Throw and Handle API Validation Errors
- Advanced API Validation With Custom Errors
- Create an API Documentation with Swagger
- Customize Your Swagger API Documentation URL
- Describe Endpoint Details in Your Swagger API Documentation
- 10 Tips on API Testing With Postman
- JWT Authentication in Swagger API Documentation
- API Versioning with Request Headers
- API Login With Username and Password to Generate a JWT
- JWT Authentication and Private API Endpoints
- Refresh Tokens With JWT Authentication
- Create a JWT Utility
- JWT Refresh Token for Multiple Devices
- Check Refresh Token in Authentication Strategy
- Rate Limit Your Refresh Token API Endpoint
- How to Revoke a JWT
- Invalidate JWTs With Blacklists
- JWT Logout (Part 1/2)
- JWT “Immediate” Logout (Part 2/2)
- A Better Place to Invalidate Tokens
- How to Switch the JWT Signing Algorithm
- Roll Your Own Refresh Token Authentication Scheme
- JWT Claims 101
- Use JWT With Asymmetric Signatures (RS256 & Co.)
- Encrypt the JWT Payload (The Simple Way)
- Increase JWT Security Beyond the Signature
- Unsigned JSON Web Tokens (Unsecured JWS)
- JWK and JWKS Overview
- Provide a JWKS API Endpoint
- Create a JWK from a Shared Secret
- JWT Verification via JWKS API Endpoint
- What is JOSE in JWT
- Encrypt a JWT (the JWE Way)
- Authenticate Encrypted JWTs (JWE)
- Encrypted and Signed JWT (Nested JWT)
- Bringing Back JWT Decoding and Authentication
- Bringing Back JWT Claims in the JWT Payload
- Basic Authentication With Username and Password
- Authentication and Remember Me Using Cookies
- How to Set a Default Authentication Strategy
- Define Multiple Authentication Strategies for a Route
- Restrict User Access With Scopes
- Show „Insufficient Scope“ View for Routes With Restricted Access
- Access Restriction With Dynamic and Advanced Scopes
- hapi - How to Fix „unknown authentication strategy“
- Authenticate with GitHub And Remember the Login
- Authenticate with GitLab And Remember the User
- How to Combine Bell With Another Authentication Strategy
- Custom OAuth Bell Strategy to Connect With any Server
- Redirect to Previous Page After Login
- How to Implement a Complete Sign Up Flow With Email and Password
- How to Implement a Complete Login Flow
- Implement a Password-Reset Flow
- Views in hapi 9 (and above)
- How to Render and Reply Views
- How to Reply and Render Pug Views (Using Pug 2.0)
- How to Create a Dynamic Handlebars Layout Template
- Create and Use Handlebars Partial Views
- Create and Use Custom Handlebars Helpers
- Specify a Different Handlebars Layout for a Specific View
- How to Create Jade-Like Layout Blocks in Handlebars
- Use Vue.js Mustache Tags in Handlebars Templates
- How to Use Multiple Handlebars Layouts
- How to Access and Handle Request Payload
- Access Request Headers
- How to Manage Cookies and HTTP States Across Requests
- Detect and Get the Client IP Address
- How to Upload Files
- Quick Access to Logged In User in Route Handlers
- How to Fix “handler method did not return a value, a promise, or throw an error”
- How to Fix “X must return an error, a takeover response, or a continue signal”
- Query Parameter Validation With Joi
- Path Parameter Validation With Joi
- Request Payload Validation With Joi
- Validate Query and Path Parameters, Payload and Headers All at Once on Your Routes
- Validate Request Headers With Joi
- Reply Custom View for Failed Validations
- Handle Failed Validations and Show Errors Details at Inputs
- How to Fix AssertionError, Cannot validate HEAD or GET requests
What are Server Labels
Labels within hapi’s server
object is a string or an array of strings representing the server. The labels
option defaults to an empty array []
. Labels are similar to tags and are used to categorize servers. Use the labels
property in combination with the server.select()
method to pick matching connections.
How to Use Labels
Let’s directly start with an example to illustrate the definition of labels for different server connections. We create three different connections and label each connection with a proper name representing its purpose.
var hapi = require('hapi');
// Create hapi server instance
var server = new hapi.Server();
// add connection parameters
server.connection({
host: 'localhost',
port: 3000,
labels: ['frontend']
});
server.connection({
host: 'localhost',
port: 3001,
labels: ['admin']
});
server.connection({
host: 'localhost',
port: 8000,
labels: ['api']
});
As you can see within the code snippet, we create a new hapi server instance and define three connections. Hapi will listen on all defined connections for incoming requests to handle. However, the important parts are the labels
definition. The first connection is labeled as frontend
since this connection represents our web frontend. The second connection has the admin
label assigned. The third connection is the api
and has the appropriate label attached.
Internally, hapi does a deep clone of the options
object passed to the server.connection
method. You can now use the server.select()
method to request a specific connection for further operations.
Select Connections by Label
Hapi’s server object offers the server.select
method to pick a single or multiple connections based on labels. The server.select
method returns an array of connections. The code below shows the connection selection using the previously introduced server configuration with their labels.
var api = server.select('api');
// api.connections.length === 1
As you expect, only the one connection labeled as api
was selected from the pool of three connections.
Combine Multiple Labels to Select Connections
We’re now deriving another example from the previously introduced hapi server configuration with three connections and their labels. We assume the frontend
and admin
connections are accessible via web browser. Therefore, both connections require view rendering support. We now want to select both connections via an OR
statement and pass an array of labels to select the frontend
and admin
connections.
// all servers with a label of frontend OR admin
var frontends = server.select(['frontend', 'admin']);
// frontends.connections.length === 2
// servers with a label of api AND admin
var apiOrAdmin = server.select('api').select('admin');
// apiOrAdmin.connections.length === 0
You can also simulate an AND
selection by chaining the select
methods and passing the specific labels as parameters. The example above tries to select a connection with label api
AND admin
which is obviously not available and results in an empty return (length === 0).
Register Plugins for Server(s) Selected by Labels
A common use case for labels is the separate installation of plugins for different connections. Within our exemplary server setup with three connections, only the frontend
and admin
connection need template rendering support. We have two options to register the vision
plugin for rendering support only to those two connections: we could either use the server.register
method or select the two connections first and register the plugins for them. The example below uses the server
object and specifies the connection selection as a parameter.
server.register({
register: require('vision')
}, {
select: ['frontend', 'admin']
}, function (err) {
// handle error
// do further stuff like view configuration, etc.
}
});
The snippet above shows you how to register a plugin only for selected connections. The api
connection doesn’t require any view support and there’s no need to add the vision
plugin to the api
as well.
We hope you’ve learned a lot about hapi’s server labels throughout this guide! Maybe you’ve already use cases in mind for your projects using hapi as the framework.
Please use the comments below or shout out to @futurestud_io for further questions!