Within a previous tutorial, you’ve already seen how to separate the frontend and backend within a single hapi project. Hapi ships with build-in support to create multiple connections which are internally handled as virtual servers that listen on different ports.
Because you’re already using multiple internal servers, you want to keep them lean and only add the functionality that is required for the given instance. Further, it’s a best-practice in hapi to use plugins to add functionality to your server and you can apply that behavior across multiple servers as well.
This tutorial will walk you through the process on how to create multiple hapi server connections and register individual plugins only for a selected instance.
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
- Extend Your Server Functionality With Plugins
- Create Your Own Custom Plugin
- How to Register Plugins for a Selected Server Instance
- hapi Plugin for Client Geo Location (by Future Studio 🚀)
- Increase Development Speed With Errors in the Browser or as JSON Response
- 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
Multiple hapi Server Connections
As a hapi developer, you’re already familiar with the server.connection()
method that defines the incoming server connection. As the return value of such method call, you’ll get a server object that is usable like you would do with new Hapi.Server()
. When adding a second connection, you’ll receive another server instance in return. For those different server instances, you can register routes and plugins and call the same methods as you would do on the actual server
object.
The following code example shows you how to create two connections: the first is labeled as frontend
and the second one as backend
. Later within this tutorial, we’ll refer to this code block with reference to it’s file name: server.js
.
server.js
var Hapi = require('hapi')
var _ = require('lodash')
var port = 3000
// create new server instance
var server = new Hapi.Server()
// add server’s connection information
var frontend = server.connection({
host: 'localhost',
port: process.env.PORT || port,
labels: 'frontend'
})
// add another server connection
var backend = server.connection({
host: 'localhost',
port: process.env.PORT + 1 || port + 1,
labels: 'backend'
})
// start your server after plugin registration
server.start(function (err) {
if (err) {
throw err
}
_.forEach(server.connections, function(connection) {
console.log('Server started at: ' + connection.info.uri)
})
})
The individual connections for frontend
and backend
use a port offset of 1 which means the backend is available on a port that is increased by one in reference to the frontend. Ultimately, you’re going to start both virtual servers for frontend and backend on their defined connections.
If you’re going to run the code snippet from above, the command line output will look like this:
$ node server.js
Server started at: http://localhost:3000
Server started at: http://localhost:3001
Due to the fact that you didn’t specify the PORT
environment variable while starting the server.js
file, the default port 3000
is used for the frontend
connection and port 3001
for the backend respectively.
Register Plugins Only for a Selected Server
The server setup is done. You’ve created two virtual server instances that can be used as two different servers with their individual functionality. Plugins are an essential component in hapi and it’s highly recommended to extend your server’s functionality using plugins.
In the following, you’ll create a simple plugin that registers a route to the calling server instance. Any further reference to this plugin is done via the chosen file name: frontend-routes.js
.
frontend-route.js
var plugin = {
register: function (server, options, next) {
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply('Frontend is totally fine')
}
})
next()
}
}
plugin.register.attributes = {
name: 'multiple-server-instances-frontend-routes',
version: '1.0.0'
}
module.exports = plugin
As you can see, the plugin code is straight forward and only adds the mentioned route to the server. Finally, the next()
method gets called to notify hapi that the plugin was added correctly and the next one can be registered.
That plugin can now be used and registered to a selected server instance. Because your plugin is dedicated to the frontend, you only want to register it to the frontend
server. Add the following lines to your server.js
file (or your chosen file name) and with that register the plugin to your frontend
instance.
frontend.register({
register: require('./frontend-route')
})
Restart your hapi server so that the changes take effect. The registered plugin adds the defined route to your frontend server which is available on port 3000
(or your chosen port). Just call http://localhost:3000
in your browser to check if everything went smooth. You should see the Frontend is totally fine
message.
You can double check your backend by navigating to http://localhost:3001
in your browser and verify that the plugin wasn’t added to the backend
server instance as well.
Outlook
This guide walked you through the setup of a hapi server that listens for incoming requests on two connections. Further, you’ve created a plugin and only registered it to one of the two server connections. That functionality allows you to separate concerns in your hapi app and also keeps a small footprint for your individual servers.
Do you have any question or just want to leave a message? Use the comments below or find us on Twitter @futurestud_io
Make it rock & enjoy coding!
Additional Resources
- Use plugins to extend your hapi server functionality
- Separate frontend and backend servers in hapi within a single project