Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dwyl/learn-hapi
:sunny: Learn to use Hapi.js (Node.js) web framework to build scalable apps in less time
https://github.com/dwyl/learn-hapi
Last synced: 15 days ago
JSON representation
:sunny: Learn to use Hapi.js (Node.js) web framework to build scalable apps in less time
- Host: GitHub
- URL: https://github.com/dwyl/learn-hapi
- Owner: dwyl
- Created: 2014-05-31T08:50:14.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2021-12-27T22:31:06.000Z (almost 3 years ago)
- Last Synced: 2024-09-22T05:18:44.479Z (about 2 months ago)
- Language: HTML
- Homepage:
- Size: 262 KB
- Stars: 795
- Watchers: 118
- Forks: 68
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
Awesome Lists containing this project
- awesome-hapi - learn-hapi - Learn to use Hapi.js (Node.js) web framework to build scalable apps in less time (Resources / Tutorials)
README
![Happiness Is...](https://i.imgur.com/Df5Z18T.jpg)
[![Build Status](https://travis-ci.org/dwyl/learn-hapi.png?branch=master)](https://travis-ci.org/dwyl/learn-hapi)
[![codecov.io test coverage](https://codecov.io/github/dwyl/learn-hapi/coverage.svg?branch=master)](https://codecov.io/github/dwyl/learn-hapi?branch=master)
[![Code Climate](https://codeclimate.com/github/dwyl/learn-hapi.png)](https://codeclimate.com/github/dwyl/learn-hapi)
[![Dependencies](https://david-dm.org/dwyl/learn-hapi.png?theme=shields.io)](https://david-dm.org/dwyl/learn-hapi)
[![devDependencies Status](https://david-dm.org/dwyl/learn-hapi/dev-status.svg)](https://david-dm.org/dwyl/learn-hapi?type=dev)
[![NPM Version][npm-image]][npm-url]
[![HitCount](https://hits.dwyl.com/dwyl/learn-hapi.svg?style=flat-square)](https://hits.dwyl.com/dwyl/learn-hapi)# Learn Hapi
Happiness is learning how to use the [**Hapi.js**](https://hapijs.com/) (Node.js) web framework to
_**build reliable/scalable apps faster**_.## What is Hapi?
Hapi is *the* framework for rapidly building RESTful & Real-Time web applications and services with Node.js.
Whether you are building a very simple API
for your website/mobile app or a large scale, cache heavy,
secure e-commerce website, hapi has you covered.
Hapi will help get your server developed quickly with its wide range
of configurable options.### *Watch* this intro/background to Hapi video:
[![What is Hapi?](https://i.imgur.com/sZRoxdD.png)](https://youtu.be/BsyvnVOhp4U?t=3m50s "What is Hapi.js - Click to Watch!")
*Most* people/teams that have _tried_ Hapi have _embraced_ Hapi to build *complete* web applications. But if you are only building a REST API (_e.g. for a mobile app_)
please read:
https://github.com/dwyl/learn-api-design## _Why_ Hapi instead of XYZ framework?
**Q**: I already know how to build REST APIs in `{framework-xyz}` why learn a *new* framework?
**A**: If you are *happy* with your existing system & level of team productivity,
stick with what you know. If not, learn [how to be] Hapi.
(We have built Sites/APIs with both Express, Restify, Sails & Meteor and find Hapi has solved more
"real world" problems and thus we end up writing less code. YMMV. See benefits below)**Q**: Hapi looks like quite a steep learning curve,
how long will it take me to learn?
**A**: You can get started *immediately* with the examples below,
it will take _approximately **60 mins** to complete_ them all (after that add a couple of hours to read/learn further).
The most important part is to ***try Hapi*** on a simple project to gain experience/confidence.### Key Benefits
- ***Performance*** - WalmartLabs are the guys who found/solved the
[Node.js *CORE* Memory Leak](https://www.joyent.com/blog/walmart-node-js-memory-leak);
they have developed Hapi following
[Benchmark Driven Development](https://github.com/felixge/faster-than-c)
and the result is a high-performance framework
+ ***Security*** - The *Lead* Developer of Hapi is [**Eran Hammer**](https://github.com/hueniverse) who was one of the original authors
of the OAuth (Secure Authentication) Spec. He has built a security-focussed
mindset into Hapi and reviews all code included in Hapi. Several members of the [Node Security Project](https://nodesecurity.io) are *core* contributors to
Hapi which means there are many security-minded eyes on the code.
- ***Scalability*** - they have focussed on *horizontal-scalability*
and battle-tested the framework during [Black Friday](https://nodeup.com/fiftysix)
(*holiday shopping busy day*) without incident.
- **Mobile Optimised** (lightweight - built for mobile e-commerce)
- **Plugin Architecture** - extend/add your own modules (good ecosystem)
- ***DevOps Friendly*** - configuration based deployment and great stats/logging see: [#logging with good](https://github.com/dwyl/learn-hapi#logging-with-good) section below!
- Built-in ***Caching*** (Redis, MongoDB or Memcached)
- ***100% Test/Code Coverage*** (for the core) - *disciplined approach to code quality*
+ ***Testability*** - End-to-End testing is ***built-in*** to Hapi because
it *includes* [**shot**](https://github.com/hapijs/shot)
- **Key Functionality** is **Built-in** and there are *many* plugins for other
features: https://hapijs.com/plugins### _In-depth Comparison_ to Express.js
@ethanmick wrote a detailed post on why _he_ prefers Hapi to Express:
https://www.ethanmick.com/why-i-like-hapi-more-than-express/ --its worth a read.
[PDF](https://github.com/dwyl/learn-hapi/files/502449/Why-I-like-Hapi-more-than-Express.pdf)### _Beginner Friendly_ Examples/Apps to Learn From/With
We have a few "_beginner_" example apps (with documentation & tests!)
that will help you get started with something a bit more "real world":+ Registration & Login (Basics): https://github.com/dwyl/hapi-login-example-postgres
+ Chat using Hapi, Redis & Socket.io: https://github.com/dwyl/hapi-socketio-redis-chat-exampleFor a _list_ of examples see: https://github.com/dwyl?&query=example
## Who (_is using Hapi_) ? [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/learn-hapi/issues)
The list of teams using Hapi.js to build their node.js apps grows every day!
See: https://hapijs.com/community> While you should _not_ make your decisions to use a given technology
based on who _else_ is using it, you should be _aware_ that
and if you need to answer the **question**:
"***Who is already using this in Production?***"
it's _really_ useful to have a good list.## _How?!_ (_Dive In_!)
## Requirements
- [x] A **computer** that can run [**Node.js**](https://nodejs.org/download/) Mac/Windows/Linux/Chromebook
- [x] Access to the Internet (only required for installation)
- [x] 60 minutes of time +/-### Optional
(_Not essential before you start, however_) You will _benefit_ from having:
+ [x] Basic JavaScript knowledge
+ [x] Basic experience of using node.js's `http` module.## Make Me Hapi ("_Official_" _Beginner Workshop_)
First thing you should do to get familiar with Hapi is work through the
[makemehapi](https://nodeschool.io/#makemehapi) workshop.
(_assumes some [node.js](https://nodeschool.io/#learn-you-node) prior
knowledge but otherwise a gentle self-paced introduction_)_Note: makemehapi currently uses Hapi v16. Some major changes were introduced to Hapi in v17. [Differences between v16 and v17](#hapi-v16)_
Create a new folder on your local machine for your answers to **makemehapi**:
```
mkdir makemehapi && cd makemehapi
```Install the workshop:
```
npm install -g makemehapi@latest
```
( if it fails to install see: https://stackoverflow.com/questions/16151018/npm-throws-error-without-sudo )Once its installed, start the tutorial with the following command:
```
makemehapi
```_Try_ to complete all challenges.
![makemehapi complete](https://i.imgur.com/luXMDmg.png)
If you get *stuck*, you can either _google_ for the specific error you are
seeing or if you are not "getting" it, you can always look at my answers in the /**makemehapi** directory of this repository ***or***
_the_ "official" solutions
in the **/makemehapi/exercises/{exercise-name}/solution** directory
e.g: https://github.com/hapijs/makemehapi/tree/master/exercises/hello_hapi/solutionor if you still don't get it, _**ask us**_:
https://github.com/dwyl/learn-hapi/issues
## _Extended_ Examples
For the rest of the tutorial we will cover the various
plugins and features we have used in the Hapi.js ecosystem
that will help you getting up-and-running with Hapi!### Recap: Hello World in Hapi
Once you have completed the **makemehapi** workshop,
on your computer, create a new directory called "**hapiapp**". e.g:```sh
mkdir hapiapp && cd hapiapp
```Type out (or copy-paste) this code into a file called **index.js**
```js
const Hapi = require('hapi');
const server = new Hapi.Server({port: 3000}); // tell hapi which TCP Port to "listen" onserver.route({
method: 'GET', // define the method this route will handle
path: '/{yourname*}', // this is how you capture route parameters in Hapi
handler: function(req, h) { // request handler method
return 'Hello ' + req.params.yourname + '!'; // reply with text.
}
});async function startServer() {
await server.start() // start the Hapi server on your localhost
console.log('Now Visit: http://localhost:' + server.info.port + '/YOURNAME');
}startServer();
module.exports = server;
```
Install Hapi:
```
npm init -y && npm install hapi --save
```
Run:
```
node .
```Visit: http://localhost:3000/YOURNAME (in your browser)
you should see something like:![hello world in hapi](https://i.imgur.com/m9qcs17.png)
### Validation with Joi
**Validation** is a fancy way of saying "checking" a value is
the **type** / **format** and **length** you expect it to be.e.g. imagine you ask people to input their phone number
and some joker enters letters instead of numbers. The validation
will display a message to the person informing the data is incorrect.[**Joi**](https://github.com/hapijs/joi) is the validation library built by
the same team as Hapi.
Most people use Joi with Hapi, but given that it is a separate
module, plenty of people use Joi independently;
its well worth checking it out!An example:
Type out (or copy-paste) this code into a file called **hellovalidate.js**```js
// Start this app from your command line with: node hellovalidate.js
// then visit: http://localhost:3000/YOURNAMEconst Hapi = require('hapi'),
Joi = require('joi');const server = new Hapi.Server({ port: 3000 });
server.route({
method: 'GET',
path: '/{yourname*}',
config: { // validate will ensure YOURNAME is valid before replying to your request
validate: {
params: {
yourname: Joi.string().min(2).max(40).alphanum().required()
}
},
handler: function (req, h) {
return 'Hello '+ req.params.yourname + '!';
}
}
});async function startServer() {
await server.start(); // start the Hapi server on your localhost
console.log('Now Visit: http://localhost:' + server.info.port + '/YOURNAME');
}startServer();
```Now try entering an _invalid_ name: http://localhost:3000/T
You should see a **Validation Error**:![Hapi Joi validation error](https://i.imgur.com/Dyhel2V.png)
This might not _look_ like a "Friendly" Error message.
But as we will see later, it provides all the information we need
in our Client/App and we can display a more user-friendly error to people.[Joi](https://github.com/hapijs/joi) has many more useful validation methods.
We will use a few of them later on when we build our example app.+ Detailed example: https://github.com/hapijs/joi#example
and https://vawks.com/blog/2014/03/22/the-joi-of-validation/
+ Want _friendly_ error messages in your web app?
see: [https://github.com/dwyl/**hapi-error**](https://github.com/dwyl/hapi-error)### Testing with Lab
If you're _new_ to Test Driven Development (**TDD**) read
our ***Beginners' TTD Tutorial***:
[https://github.com/dwyl/**learn-tdd**](https://github.com/dwyl/learn-tdd) (_first_)
and then come _back_ to this tutorial!If you've done functional or unit testing in previous
programming projects you will be at home with Lab.Lab borrows *heavily* from [Mocha](https://github.com/mochajs/mocha),
so if you followed our
[learn-mocha](https://github.com/dwyl/learn-mocha) tutorial this should all be familiar.(Using the code we wrote above in the **Validation with Joi** section with a minor addition)
An example of testing with Lab:```js
const Lab = require("lab"); // load Lab module
const lab = exports.lab = Lab.script(); //export test script
const Code = require("code"); //assertion library
const server = require("../examples/hellovalidate.js");lab.experiment("Basic HTTP Tests", function() {
// tests
lab.test("GET /{yourname*} (endpoint test)", async function() {
const options = {
method: "GET",
url: "/Timmy"
};
// server.inject lets you simulate an http request
const response = await server.inject(options);
Code.expect(response.statusCode).to.equal(200); // Expect http response status code to be 200 ("Ok")
Code.expect(response.result).to.have.length(12); // Expect result to be "Hello Timmy!" (12 chars long)
await server.stop();
});
});
```
First we create a *test suite* for our test **Lab.experiment**
(the _first argument_ is the name of the test suite "Basic HTTP Tests")Next is a basic test that calls the only route we have `/{yourname}`
in this case **GET /Timmy**.
We expect to receive a **200** http status code and the response body to be
the text "Hello Timmy!".1. Create a **new directory** in your project called **test**
2. Create a **new file** called **test.js** in the **./test** dir
3. Type out or copy-paste the above code into **test.js**
4. Open your package.json file
5. Add a **scripts** section to the package.json file with the following:
```
"scripts": {
"test": "lab -c"
}
```
6. Save the package.json file
7. run the **npm test** script from your command line to execute the testsThe result should look something like this:
Note how the test script has a `-c` (_coverage_) flag above
this give us the **code coverage**.We have **100% code coverage** so we can move on to our next test/feature!
> How do you think we would write a test for an error?
> (hint: have a look inside ./test/test.js and see the second test :)### Note on Testing: Tape is _Simpler_ than Lab+Code
> *While* ***Lab*** *is really* ***Good*** *and is the "official" testing
framework used by Hapi*, *we* ***prefer***
*the* ***simplicity***
> *of* [***tape***](https://github.com/substack/tape);
> we find our tests are simpler to write/read/understand. #YMMV
> Also we *prefer* to use a *separate* & *specialised* module for tracking
test coverage: [istanbul](https://github.com/dwyl/learn-istanbul)
which we find does a [better job](https://github.com/hapijs/lab/issues/401) at tracking coverage...The preceding `Lab` test can be re-written (*simplified*) in `Tape` as:
```js
const test = require('tape');
const server = require("../index.js"); // our index.js from abovetest("Basic HTTP Tests - GET /{yourname*}", async function(t) { // t
const options = {
method: "GET",
url: "/Timmy"
};
// server.inject lets you similate an http request
const response = await server.inject(options);
t.equal(response.statusCode, 200); // Expect http response status code to be 200 ("Ok")
t.equal(response.result.length, 12); // Expect result to be "Hello Timmy!" (12 chars long)
await server.stop();
t.end(); // t.end() is required to end the test in tape
});
```
These tests are *functionally equivalent* in that they test *exactly* the
same *outcome*. Decide for yourself which one you prefer for readability
and maintainability in your projects.
For our **Tape Tutorial** see: https://github.com/dwyl/learn-tape#### Related Links
- Lab github module: https://github.com/hapijs/lab
- Is TDD Dead? https://www.youtube.com/watch?v=z9quxZsLcfo (hint: no!)
- Getting Started with HapiJS and Testing: https://blog.abcedmindedness.com/2014/10/getting-started-with-hapijs-and-testing.html (on hapi v8.0)## Continuous Integration
Making sure your code is working as you expect it to (over time).
### Integrating Hapi with Travis CI
If you are new to Travis-CI or need a refresher see: https://github.com/dwyl/learn-travis
We have Travis-CI enabled for all our hapi.js based projects:
+ https://github.com/dwyl/hapi-socketio-redis-chat-example
+ https://github.com/dwyl/hapi-auth-jwt2
+ https://github.com/dwyl/time
+ https://github.com/dwyl/apiSo if you need an example to follow, check out our repos!
And as always, if you have _any questions, **ask**_!### Error Handling with Boom
[Boom](https://github.com/hapijs/boom) makes custom errors easier in Hapi.
Imagine you have a page or item of content (photo, message, etc.) that
you want to protect from public view (only show to someone who is logged in).First **install boom**:
`npm install boom --save`
Next write another test in ./test/**test.js**
(If you aren't used to "Test First" - ***trust*** the process...)```js
lab.experiment("Authentication Required to View Photo", function() {
// tests
lab.test("Deny view of photo if unauthenticated /photo/{id*} ", async function() {
const options = {
method: "GET",
url: "/photo/8795"
};
// server.inject lets you simulate an http request
const response = await server.inject(options);
Code.expect(response.statusCode).to.equal(401); // Expect http response status code to be 200 ("Ok")
Code.expect(response.result.message).to.equal("Please log-in to see that"); // (Don't hard-code error messages)
});
});
```When you run `npm test` you will see a fail:
Next we want to make this test pass and we'll use Boom to get our custom error message.
The wrong way of doing this is to explicitly hard-code the response for this route.
The right way is to create a generic route which responds to any request for a photo with any id.
And since we don't currently have any authentication set up, we ***mock*** (fake) it.
(Don't worry we will get to the authentication in the next step...)```js
const Boom = require('boom');
server.route({
method: 'GET',
path: '/photo/{id*}',
config: { // validate will ensure `id` is valid before replying to your request
validate: { params: { id: Joi.string().max(40).min(2).alphanum() } },
handler: function (req, h) {
// until we implement authentication we are simply returning a 401:
return Boom.unauthorized('Please log-in to see that');
// the key here is our use of the Boom.unauthorised method
}
}
});
```Our test passes but the point was to show that returning errors
with specific messages is *easy* with **Boom**.Have a look at https://github.com/hapijs/boom for more error response options.
We will be using these later as we build our app.
Let's move on to authentication.> For a more _user-friendly_ approach to error-handling see: https://github.com/dwyl/hapi-error
### Logging with `good`
Application logging can often be an _afterthought_ developers only implement
_after_ they have a production bug which is crashing their API/App and
they are scrambling to try and "debug" it.Thankfully, it Hapi has first-class support for logging with the `good` module.
We have written a little example you can use to get started:
[examples/hellogood.js](https://github.com/dwyl/learn-hapi/blob/master/examples/hellogood.js)Run it locally with `node examples/hellogood.js` then visit http://localhost:3000/hello/yourname in your browser.
_Note: Good is not yet compatible with Hapi 17, so this code will only run if you are using v16. [See here for more details](#hapi-v16)_
You should expect to see something like this:
![learn-hapi-good-log-two-ops](https://cloud.githubusercontent.com/assets/194400/18990153/051440e8-8708-11e6-9337-bcc2ab067853.png)There are good examples including logging use http (e.g. to a 3rd party logging tool)
in the Good repo: https://github.com/hapijs/good/tree/master/examplesAgain, if you have _any_ questions, [_ask_](https://github.com/dwyl/learn-hapi/issues)
### Authentication
Authentication is the process of determining whether someone
or something is, in fact, who or what it is declared to be.Authentication (or "Auth") is something many *novice* (*naive*?)
developers attempt to write themselves. (I was once that kid...
trust me, we have *bigger fish to fry*, use a well-written/tested library!)We have 4 options:
1. Google - If you are building an "enterprise" or "education" app
which you know will be used in Google-enabled companies/schools we
wrote a Hapi plugin: https://github.com/dwyl/hapi-auth-google which
lets you include Google Login in your app in a few clear steps. The plugin uses the [***Official Google Node.js API Client***](https://github.com/google/google-api-nodejs-client) and is
written to be as readable as possible for complete beginners.
2. EveryAuth - Specific to Connect/Express apps: https://github.com/bnoguchi/everyauth
3. [Passport.js](https://github.com/jaredhanson/passport) - ***100% Code Coverage*** and *many* excellent integrations https://passportjs.org/guide/providers/
4. Bell - the 3rd party Login Hapi.js Plugin is *good* however we found it
*lacking in documentation/usage examples*, which is why we wrote
our own (*simpler*) Auth Plugin *specific* to our projects.
see: [https://github.com/**dwyl**?query=**auth**](https://github.com/dwyl?utf8=%E2%9C%93&query=auth)#### Bell
The go-to solution for 3rd party authentication in hapi is bell: https://github.com/hapijs/bell.
There are a few good examples in the repo: https://github.com/hapijs/bell/tree/master/examples.### Caching with Catbox
Most apps don't _need_ caching from "Day 1"
(_because you don't **know** upfront where your app's bottlenecks are going to be..._).But, once again, the team that brought you Hapi.js have _solved_ the problem of caching,
see: https://github.com/hapijs/catbox/ and https://hapijs.com/tutorials/caching
> We use Redis for blazing fast application and data caching.
Hapi.js Catbox makes this very easy!### Using Socket.io with Hapi for Real-Time Apps
Using Socket.io with Hapi.js could _not_ be easier!
To help you get started we've built a fully-functional chat application with tests (now [featured on the hapijs.com Resources page](https://hapijs.com/resources#Tutorials)),
which demonstrates the power of Real-Time data-synching in your apps.> https://github.com/dwyl/hapi-socketio-redis-chat-example
## Hapi v16
There were some major changes introduced to Hapi when version 17 was released. For a full list, see [the version 17 release notes](https://github.com/hapijs/hapi/issues/3658), but here are the major differences relevant to this guide:
* Callbacks replaced with `async` functions. This means that instead of passing a callback to the function, and having that called when the function is finished, hapi functions return a promise that can either be resolved, or called synchronously with `await`. For more on `async` functions, see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) and [this guide](https://ponyfoo.com/articles/understanding-javascript-async-await)
* `server.connection()` replaced with options passed directly into the server when it's created. A small change, but important to update. Before, we created our server with:
```js
var server = new Hapi.server();
```
and passed our options to:
```js
server.connection({port: 8000});
```
Now, we just pass our options straight away, and no longer need to call the connection method:
```js
const server = new Hapi.server({port: 8000});
```
* `reply()` interface replaced with a new lifecycle methods interface. You no longer have to call reply when sending a response from a handler. You can now just:
```js
return "your reply";
```
And the reply parameter to your handler has been replaced with a response toolkit (h) containing helpers from hapi core and your plugins.Not all of the hapi plugins have been updated to work with v17 yet (For example [Bell](https://github.com/hapijs/bell/issues/330), and [Good](https://github.com/hapijs/good/issues/568)), so be careful if you decide to upgrade an existing project.
The previous version of this tutorial and code examples for Hapi 16 can be found here: https://github.com/dwyl/learn-hapi/tree/b58495ea002a9f3f8af8d183f6004d2b483f4591
## Please Suggest Improvements! [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/learn-hapi/issues)
If you want to extend this tutorial or simply request additional sections,
open an issue on GitHub: https://github.com/dwyl/learn-hapi/issues## Background Reading / Watching
- GitHub Repo: https://github.com/hapijs/hapi (has documentation)
- An ecosystem of tools and best practices for the working hapijs developer (up-to-date with last version of hapi): https://hapipal.com/ https://hapipal.com/getting-started- Restify vs Express performance: https://stackoverflow.com/questions/17589178/why-should-i-use-restify
- REST API in Express: https://pixelhandler.com/posts/develop-a-restful-api-using-nodejs-with-express-and-mongoose
- Hapi API Reference: https://github.com/hapijs/hapi/blob/master/API.md### Video Intro
- Hapi.js and why it's awesome: https://www.youtube.com/watch?v=ZI9wXL-add0&t=2m5s
- Hapi overview: https://www.youtube.com/watch?v=Recv7vR8ZlA (old version but concepts still relevant)### Tutorials
- Hapi Boilerplate app: https://github.com/poeticninja/hapi-ninja [updated for hapi 8.0]
- Building APIs with Hapi and MongoDB: https://speakerdeck.com/donnfelker/building-web-apis-with-hapi-dot-js-and-mongodb-mongoose
- Repo for the above speakerdeck: https://github.com/donnfelker/hapi-mongodb-example
- Micro-tutorial: https://github.com/hapijs/makemehapi
- https://stackoverflow.com/questions/21455076/hapi-and-node-js-to-create-a-rest-api-server
- Hapi + Twilio (sms): https://code.tutsplus.com/tutorials/creating-a-node-web-app-with-hapi-and-twilio-integration--cms-20769
- Authentication: https://github.com/hapijs/hapi-auth-cookie
- A few examples: https://github.com/andyroyle/hapi-examples
- More examples: https://github.com/wpreul/hapikc (*very old* version of Hapi!)
- BDD with Hapi and Lab: https://gist.github.com/thebillkidy/10a11fed1bf61d04c3c5 (*old* version of Hapi!)
+ If you like React.js checkout Mullet.js (Hapi.js + React.js):
https://mullet.io/ + https://github.com/lynnaloo/mullet
+ If you have an *existing* ***Express*** App and are thinking of
migrating to Hapi, read: https://matt-harrison.com/moving-from-express-to-hapi-js/Selected StackOverflow Questions & Answers:
- https://stackoverflow.com/questions/22934340/hapi-js-api-authentication
see: https://stackoverflow.com/a/33877047/1148249 (*answer*)
- https://stackoverflow.com/questions/22985392/how-do-you-make-a-hapi-js-plugin-module
see: https://stackoverflow.com/a/25135343/1148249 (*answer*)
- https://stackoverflow.com/questions/18343509/hapi-js-with-socket-io-where-is-socket-io-js
see: https://stackoverflow.com/a/33876615/1148249 (*answer*[npm-image]: https://img.shields.io/npm/v/hapi.svg?style=flat
[npm-url]: https://npmjs.org/package/learn-hapi