Are you Hapi(.js)? (Part 1/2)

László Harri Németh
The Coding Hype
Published in
9 min readMar 5, 2019
Photo by rawpixel on Unsplash

Hapi.js is “A rich framework for building applications and services”. In the present article I will make some experiments with Hapi.js framework. I will show some simple scenarios using the framework. As a reference I use Make Me Hapi, which is a self-guided workshop to teach Hapi. I found it extremely useful for learning the basics of Hapi.js, and in this article I explain the official solutions for the exercises of the workshop. I modified the official solutions in some cases, therefore they will not always be run by the workshop.

This article is the first part of a two-part series.

Keywords: Node.js, NPM, Javascript, Hapi.js, HTTP, Linux, Ubuntu, Template Engine, Inert, Path, Vision, Handlebars.js, H2o2, Routing, Static files, Directories, Templates, Proxy server

DISCLAIMER: THE VIEWS AND OPINIONS EXPRESSED IN THIS ARTICLE ARE THOSE OF THE AUTHOR AND DO NOT REFLECT THE OFFICIAL POLICY OR POSITION OF THE EMPLOYER OF THE AUTHOR. THE ARTICLE IS NOT ENDORSED BY, DIRECTLY AFFILIATED WITH, MAINTAINED, AUTHORIZED, OR SPONSORED BY ANY CORPORATION OR ORGANIZATION. THE INFORMATION CONTAINED ON THIS ARTICLE IS INTENDED SOLELY TO PROVIDE GENERAL GUIDANCE ON MATTERS OF INTEREST FOR THE PERSONAL USE OF THE READER, WHO ACCEPTS FULL RESPONSIBILITY FOR ITS USE. ALTHOUGH THE AUTHOR HAS MADE EVERY EFFORT TO ENSURE THAT THE INFORMATION IN THIS ARTICLE WAS CORRECT AT THE TIME OF THE WRITING, THE AUTHOR DOES NOT ASSUME AND HEREBY DISCLAIM ANY LIABILITY TO ANY PARTY FOR ANY LOSS, DAMAGE, OR DISRUPTION CAUSED BY ERRORS OR OMISSIONS, WHETHER SUCH ERRORS OR OMISSIONS RESULT FROM NEGLIGENCE, ACCIDENT, OR ANY OTHER CAUSE.

Programming languages, technology

This article involves the following programming languages and technology:

  • Javascript
  • Node.js
  • hapi.js
  • HTTP
  • Linux

The following node modules and Javascript libraries are used:

  • hapi.js
  • inert
  • path (core module)
  • vision
  • handlebars.js
  • h2o2

Table of Contents

The article is divided into the following sections:

  • Preparation, prerequisites
  • 1.: Simple server
  • 2.: Simple routing
  • 3.: Serving static files
  • 4.: Directories
  • 5.: Templates
  • 6.: Proxies
  • 7.: Helper scripts
  • Closing words
  • License
  • References

Preparation, prerequisites

The development environment I use is based on Ubuntu Linux 14.04.5 LTS (trusty), Nodejs v11.3.0, npm 6.4.1, nvm 0.33.11. I assume these are installed in your system. I’m using Cloud 9 environment.

To intall Hapi, you need to run

npm install hapi

Version of Hapi I use is 17.8.1.

In these examples I use process.env.IP and process.env.PORT instead of localhost and 8080. This is because of the Cloud 9 environment.

1.: Simple server

First this is an example of a simple web server.

The app will show a “Hello hapi” text in the browser. It is important to observe how to start the server. It is put to an async function, and the server is started with await server.start().

2.: Simple routing

In the previous example '/' was provided as path attribute. Paths can contain named parameters. In the example below, the parameter name is name and it is returned by accessing with request.params.name.

About encodeURIComponent(): according to the documentation, it “encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two “surrogate” characters).”.

3.: Serving static files

In order to send static files to the client an additional module is needed. This module is inert (current version is 5.1.2), which is installed with:

npm install inert

For this example need an additional module is used, which is the core modulepath. This example also contains an HTML file.

The server serves index.html to the client, when it is accessed with path /.

Solution 1

I needed to modify the coding because inter module must be registered for the server. Therefore server.route() calls are put in the initialization. In the end, I put the call to Hapi.Server() also in the initialization.

It is important to care about the proper file path on the server, for this we need to use Path.join(__dirname, 'index.html');.

I left the code from the previous example here, so that paths like /name are also served.

Solution 2

As an alternative solution it is possible to configure a base path in your server and only pass relative path. The base path can be specified in routes. This way I can use index.html without specifying the absolute path.

4.: Directories

With the directory handler it is possible to access a file in a directory with a different path in the URL. It makes possible to specify one route to serve multiple files. The below route will respond to any request by looking for a matching filename in /foo/bar/baz directory. But it would respond with HTTP 403 if the directory itself is accessed without a file in the path. With the highlighted part of the code this can be fixed:

server.route({
path: '/foo/bar/baz/{param*}',
method: 'GET',
handler: {
directory: {
path: Path.join(__dirname, 'public'),
index: ['index.html', 'default.html']
}
}
});

When there is no index file available, inert can display the contents of the directory as a listing page. You can enable that by setting the listingproperty to true like so:

server.route({
path: '/foo/bar/baz/{param*}',
method: 'GET',
handler: {
directory: {
path: Path.join(__dirname, 'public'),
listing: true
}
}
});

(The above two features are not included in the example below.)

In this example below we have a file.html in the /public directory of the server, and access this file with the /foo/bar/baz/file.html path. (We could access other files in the same /public path as well.)

5.: Templates

This exercise shows the templating possibilities using Hapi.js. For this two additional modules are used:

  • vision
  • handlebars.js

Let’s install these:

node install vision handlebars

For this example Inert module is not needed.

The vision plugin needs to be registered for the server:

// Register Vision plugin
await server.register(Vision);

Also Handlebars module needs to be registered so that the templates will work. Handlebars is the engine responsible for rendering templates with an extension of .html.

// Register Handlebars to handle templates
server.views({
engines: {
html: Handlebars
},
path: Path.join(__dirname, 'templates')
});

In this example the server is called with /?name=World and it will process the templates in the /templates directory. As it can be seen, the index.html is a special HTML file which contains references which can be processed by Handlebars.js. With {{query.name}} the name parameter is referenced, and the content of it is put to the HTML page, which is sent back to the client.

The implementation is the following:

6.: Proxies

In this exercise a proxy server is implemented. For this module h2o2 is needed.

npm install -g h2o2

H2O2 is a proxy handler for Hapi.js. For this exercise there are 2 scripts. The first server is a proxy server running on port 8080 and this connects to the other server. When the proxy server is accessed with path /proxy it will connect to the another server. The other server is running on port 65535. This one will serve an HTML page. The two servers need to be run at the same time.

In the following code snippets the index.html file is served by the target server — under target server I mean the server which is accessed by the proxy server.

The script makemehapi-exercise-6-proxy.js contains the implementation of the proxy server. This will require h2o2, and set a proxy in the handler of the server route /proxy. This script needs to be run with node makemehapi-exercise-6-proxy.js.

The script makemehapi-exercise-6-target.js is the “target” server. This needs to be run with node makemehapi-exercise-6-target.js 65535.

In computer networks, a proxy server is a server (a computer system or an application) that acts as an intermediary for requests from clients seeking resources from other servers. A client connects to the proxy server, requesting some service, such as a file, connection, web page, or other resource available from a different server and the proxy server evaluates the request as a way to simplify and control its complexity.

Proxy server (source: Wikipedia)

Communication between two computers (shown in grey) connected through a third computer (shown in red) acting as a proxy. Bob does not know to whom the information is going, which is why proxies can be used to protect privacy. (Source: Wikipedia)

7.: Helper scripts

Further reading: Views, section “View helpers”.

In Hapi.js it is possible to define view helpers. These are helper functions which can be used in the templates. In the following example the application prints out a fruit name, for which a parameter is received from the URL.

In the example below, helper.js should be in folder helpers. This helpers folder is registered in the server with the following:

server.views({
engines: {
html: Handlebars
},
path: __dirname,
helpersPath: Path.join(__dirname, 'helpers')
});

The helper an implementation of a function which returns a value, which will be then used in the template, when the helper is referenced. For example, a simple helper.js file in the helpers folder looks like the following:

module.exports = function (context) {
value = "";
// ... implementation here ... // returning the value
return value;
};

Context is passed to the helper method.

In the template this is referenced with the name of the helper. For example, in a p tag:

<p>{{helper}}</p>

In the helper implementation, with the context.data.root.query the query parameters in the URL can be accessed. For example in the URL

https://localhost/?fruitName=3

the value of fruitName can be accessed with:

context.data.root.query.fruitName

The example of helpers looks like the following. In this example fruits.js should be in the helpers folder.

Closing words

I hope you have learned something new today. Thank you for reading this article.

License

The code snippets used in this article are based on the original solutions for the workshop, therefore I reproduce here the license of makemehapi workshop. This is relevant for the code snippets posted in this article.

Copyright (c) 2012-2014, Walmart and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
* The names of any contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * *The complete list of contributors can be found at: https://github.com/hapijs/makemehapi/graphs/contributors

Original version of the License:

References

--

--

László Harri Németh
The Coding Hype

Software developer. Python, SQL, ABAP, Swift, Javascript, Java, C, C++, Ruby, noSQL, Bash, Linux. http://nlharri.hu http://github.nlharri.hu hello@nlharri.hu