├── .gitignore ├── LICENSE ├── README.md ├── hapi-16 ├── 404-route-and-handler │ ├── base │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ └── views │ │ ├── 404.html │ │ ├── index.html │ │ └── layout.html ├── authenticate-with-github │ ├── authentication │ │ └── index.js │ ├── connect-with-github │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ └── views │ │ ├── authenticated.html │ │ ├── index.html │ │ └── layout.html ├── authenticate-with-gitlab │ ├── authentication │ │ └── index.js │ ├── connect-with-gitlab │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ └── views │ │ ├── authenticated.html │ │ ├── index.html │ │ └── layout.html ├── basic-auth │ ├── basic-routes.js │ ├── server.js │ └── views │ │ ├── index.html │ │ ├── layout.html │ │ └── success.html ├── bell-custom-oauth │ ├── authentication │ │ └── index.js │ ├── connect-with-your-server │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ └── views │ │ ├── authenticated.html │ │ ├── index.html │ │ └── layout.html ├── cookie-auth │ ├── cookie-routes.js │ ├── server.js │ ├── users-db.js │ └── views │ │ ├── index.html │ │ ├── layout.html │ │ └── profile.html ├── cookies-store-and-read │ ├── base-route.js │ └── server.js ├── default-auth-strategy │ ├── routes.js │ ├── server.js │ └── users-db.js ├── different-default-handlebars-layouts │ ├── index │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ └── views │ │ ├── index.html │ │ ├── layout.html │ │ └── second-layout.html ├── extend-hapi-with-plugins │ └── server.js ├── getting-started │ └── server.js ├── hapi-vue-ssr-basic │ ├── base │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ └── views │ │ ├── about.html │ │ ├── index.html │ │ └── layout.html ├── ignore-trailing-slash-on-paths │ ├── base-route.js │ └── server.js ├── multiple-auth-strategies-for-routes │ ├── routes.js │ ├── server.js │ ├── users-db.js │ └── views │ │ ├── index.html │ │ ├── layout.html │ │ └── profile.html ├── multiple-server-instances │ ├── backend-route.js │ ├── frontend-route.js │ └── server.js ├── optional-path-params │ ├── base-route.js │ └── server.js ├── package.json ├── path-params-of-same-name │ ├── base-route.js │ └── server.js ├── query-params │ ├── base-route.js │ └── server.js ├── redirect-to-previous-page-after-login │ ├── authentication │ │ └── index.js │ ├── implementation │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ ├── users-db.js │ └── views │ │ ├── index.html │ │ ├── layout.html │ │ ├── login.html │ │ ├── private.html │ │ └── profile.html ├── render-handlebars-views │ ├── server.js │ └── views │ │ ├── index.html │ │ └── layout.html ├── reply-json │ ├── base-route.js │ └── server.js ├── request-headers │ ├── base-route.js │ └── server.js ├── request-payload │ ├── base-route.js │ └── server.js ├── response-status-codes │ ├── base-route.js │ └── server.js ├── restrict-access-with-scopes │ ├── base-routes.js │ ├── server.js │ ├── users-db.js │ └── views │ │ ├── admin.html │ │ ├── index.html │ │ ├── layout.html │ │ └── profile.html ├── routing │ ├── base-route.js │ └── server.js ├── serve-static-files │ ├── base-route.js │ ├── files │ │ ├── js │ │ │ └── test.js │ │ └── main.js │ └── server.js ├── show-error-stacktrace-in-browser │ ├── base │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ ├── show-error-stacktrace │ │ ├── error.html │ │ └── index.js │ └── views │ │ ├── 404.html │ │ ├── error.html │ │ ├── index.html │ │ └── layout.html ├── testing-inject-requests │ ├── .eslintignore │ ├── .eslintrc.js │ ├── base │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── package.json │ ├── server.js │ └── test │ │ ├── before-and-after-test-actions.js │ │ ├── inject-payload-headers-params.js │ │ └── plugin-index-responds-with-json.js ├── upload-files │ ├── base-route.js │ └── server.js ├── validation-parameters-and-payload │ ├── base-route.js │ └── server.js ├── validation-path-parameter │ ├── base-route.js │ └── server.js ├── validation-payload │ ├── base-route.js │ └── server.js ├── validation-query-parameter │ ├── base-route.js │ └── server.js ├── validation-request-headers │ ├── base-route.js │ └── server.js ├── validation-return-all-errors │ ├── base-route.js │ └── server.js ├── vuejs-and-handlebars │ ├── index │ │ ├── handler.js │ │ ├── index.js │ │ └── routes.js │ ├── server.js │ └── views │ │ ├── index.html │ │ └── layout.html ├── wildcard-path-params │ ├── base-route.js │ └── server.js └── write-your-own-plugin │ ├── base-route.js │ └── server.js └── hapi-18 ├── .eslintrc.json ├── package.json └── redirect-including-request-payload └── redirect-including-request-payload.js /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore premium Tutorials 2 | premium 3 | 4 | 5 | # Logs 6 | logs 7 | *.log 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directory 30 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 31 | node_modules 32 | package-lock.json 33 | 34 | # Vagrant 35 | .vagrant 36 | 37 | # IDEA (Webstorm) 38 | .idea 39 | 40 | # Visual Studio Code 41 | .vscode 42 | 43 | # bcrypt windows 44 | build 45 | src 46 | binding.gyp 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2019 Future Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hapi Tutorial Series 2 | This repository contains code examples for the [hapi tutorial series with **100+ tutorials**](https://futurestud.io/tutorials/hapi-get-your-server-up-and-running). The hapi tutorial series is published within the Future Studio University. 3 | 4 | 5 | 6 | 7 | 8 | 9 | ## YouTube Playlist 10 | Find a [playlist on YouTube with videos on the individual tutorials](https://www.youtube.com/watch?v=-o6IxDy3pIk&list=PLpUMhvC6l7AMXP2bWhHF6UTZGseIkWUG_). Each video is related to a tutorial and walks you through the implementation of an individual feature. It’s all practical, watch me live code :) 11 | 12 | 13 | ------ 14 | 15 |

This hapi tutorial series is sponsored by Future Studio University 🚀 16 |
17 | Join the Future Studio University and Skyrocket in Node.js 18 |

19 | 20 | ------ 21 | 22 | 23 | ## Dependencies 24 | You need the following tools installed on your machine to actually run the individual examples: 25 | 26 | - Node.js v4+ 27 | - NPM 28 | 29 | 30 | ## Setup 31 | To set up the required environment, just clone this repository to your local machine and install the NPM dependencies. 32 | 33 | ``` 34 | $ git clone git@github.com:fs-opensource/nodejs-tutorials-hapi.git 35 | $ cd nodejs-tutorials-hapi 36 | $ npm i 37 | ``` 38 | 39 | 40 | ## Run Examples 41 | Every example code contains its own hapi server that kicks off at `localhost:3000`. 42 | 43 | ``` 44 | $ cd examples 45 | $ cd 46 | $ node server 47 | ``` 48 | 49 | Many examples allow you to check them out within the browser. Navigate your browser to the url `localhost:3000` with a running example server in the background. 50 | 51 | 52 | ## Do you wanna see a specific example? 53 | Don't worry, just let us know :) You can file an idea within our [university-ping](https://github.com/fs-opensource/university-ping/issues/new) repository and let us know about anything you're interested to see! 54 | 55 | Enjoy coding & make it rock! 56 | -------------------------------------------------------------------------------- /hapi-16/404-route-and-handler/base/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Boom = require('boom') 4 | 5 | const Handler = { 6 | index: { 7 | handler: (request, reply) => { 8 | reply.view('index') 9 | } 10 | }, 11 | 12 | missing: { 13 | handler: (request, reply) => { 14 | const accept = request.raw.req.headers.accept 15 | 16 | // take priority: check header if there’s a JSON REST request 17 | if (accept && accept.match(/json/)) { 18 | return reply(Boom.notFound('Fuckity fuck, this resource isn’t available.')) 19 | } 20 | 21 | reply.view('404').code(404) 22 | } 23 | } 24 | } 25 | 26 | module.exports = Handler 27 | -------------------------------------------------------------------------------- /hapi-16/404-route-and-handler/base/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.dependency([ 'vision' ]) 7 | 8 | server.route(Routes) 9 | server.log('info', 'Plugin registered: 404 handler') 10 | 11 | next() 12 | } 13 | 14 | exports.register.attributes = { 15 | name: '404-handler', 16 | version: '1.0.0' 17 | } 18 | -------------------------------------------------------------------------------- /hapi-16/404-route-and-handler/base/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: [ 'GET', 'POST' ], 13 | path: '/{path*}', 14 | config: Handler.missing 15 | } 16 | ] 17 | 18 | module.exports = Routes 19 | -------------------------------------------------------------------------------- /hapi-16/404-route-and-handler/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('vision') 18 | }, 19 | { 20 | register: require('./base') 21 | } 22 | ], err => { 23 | if (err) { 24 | throw err 25 | } 26 | 27 | server.views({ 28 | engines: { 29 | html: require('handlebars') 30 | }, 31 | path: __dirname + '/views', 32 | layout: 'layout', 33 | context: { 34 | title: '404 — Nothing here' 35 | } 36 | }) 37 | 38 | // start your server 39 | server.start(err => { 40 | 41 | if (err) { 42 | throw err 43 | } 44 | 45 | console.log('Server running at: ' + server.info.uri) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /hapi-16/404-route-and-handler/views/404.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

404!

5 |

6 | Uh, shit. Fuckity fuck! This resource isn’t available. 7 |

8 | 9 |
10 | 11 |

12 | Better go back to safe lands, like the 13 | startpage 14 |

15 |
16 |
17 | -------------------------------------------------------------------------------- /hapi-16/404-route-and-handler/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Hello!

5 | 6 |

7 | Go anywhere, you’ll see the 404 :) 8 |

9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /hapi-16/404-route-and-handler/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | {{{ content }}} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/authentication/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hoek = require('hoek') 4 | 5 | exports.register = function (server, options, next) { 6 | // declare dependency to hapi-auth-cookie and bell 7 | server.register([ 8 | { 9 | register: require('hapi-auth-cookie') 10 | }, 11 | { 12 | register: require('bell') 13 | } 14 | ], err => { 15 | Hoek.assert(!err, 'Cannot register authentication plugin') 16 | 17 | /** 18 | * Register session based auth strategy to store 19 | * credentials received from GitHub and keep 20 | * the user logged in 21 | */ 22 | server.auth.strategy('session', 'cookie', { 23 | password: 'ThisIsASecretPasswordForTheAuthCookie', 24 | redirectTo: '/', 25 | isSecure: process.env.NODE_ENV === 'production' 26 | }) 27 | 28 | /** 29 | * Register 'github' authentication strategy 30 | */ 31 | server.auth.strategy('github', 'bell', { 32 | provider: 'github', 33 | password: 'ThisIsASecretCookiePasswordForGitHub', 34 | clientId: 'aee4fc96cc87416273cd', 35 | clientSecret: '5a0885bd00510c16931102459aea74063ea7c505', 36 | isSecure: process.env.NODE_ENV === 'production' 37 | }) 38 | 39 | server.log('info', 'Plugin registered: bell authentication with strategy »github«') 40 | 41 | next() 42 | }) 43 | } 44 | 45 | exports.register.attributes = { 46 | name: 'authentication', 47 | version: '1.0.0', 48 | once: true 49 | } 50 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/connect-with-github/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = { 4 | index: { 5 | auth: { 6 | mode: 'try', 7 | strategy: 'session' 8 | }, 9 | plugins: { 10 | 'hapi-auth-cookie': { 11 | redirectTo: false 12 | } 13 | }, 14 | handler: function (request, reply) { 15 | if (request.auth.isAuthenticated) { 16 | return reply.view('authenticated', request.auth.credentials) 17 | } 18 | 19 | reply.view('index') 20 | } 21 | }, 22 | 23 | /** 24 | * used to authenticate 25 | */ 26 | connect: { 27 | auth: 'github', 28 | handler: function (request, reply) { 29 | if (request.auth.isAuthenticated) { 30 | const user = request.auth.credentials.profile 31 | const data = { 32 | name: user.displayName, 33 | username: user.username, 34 | avatar: user.raw.avatar_url 35 | } 36 | 37 | request.cookieAuth.set(data) 38 | return reply.view('authenticated', data) 39 | } 40 | 41 | reply.view('index', { 42 | error: 'There was an issue with the GitHub authentication.' 43 | }).code(400) 44 | } 45 | }, 46 | 47 | logout: { 48 | auth: 'session', 49 | handler: function (request, reply) { 50 | request.cookieAuth.clear() 51 | reply.view('index') 52 | } 53 | } 54 | } 55 | 56 | module.exports = Handler 57 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/connect-with-github/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.register([ 7 | { 8 | register: require('vision') 9 | }, 10 | { 11 | register: require('./../authentication') 12 | } 13 | ], err => { 14 | if (err) { 15 | throw err 16 | } 17 | 18 | server.route(Routes) 19 | server.log('info', 'Plugin registered: connect to GitHub') 20 | 21 | next() 22 | }) 23 | } 24 | 25 | exports.register.attributes = { 26 | name: 'connect-to-github', 27 | version: '1.0.0' 28 | } 29 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/connect-with-github/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: 'GET', 13 | path: '/auth/github', 14 | config: Handler.connect 15 | }, 16 | { 17 | method: 'GET', 18 | path: '/logout', 19 | config: Handler.logout 20 | } 21 | ] 22 | 23 | module.exports = Routes 24 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('./connect-with-github') 18 | } 19 | ], function (err) { 20 | if (err) { 21 | throw err 22 | } 23 | 24 | server.views({ 25 | engines: { 26 | html: require('handlebars') 27 | }, 28 | path: __dirname + '/views', 29 | layout: 'layout' 30 | }) 31 | 32 | // start your server 33 | server.start(function (err) { 34 | 35 | if (err) { 36 | throw err 37 | } 38 | 39 | console.log('Server running at: ' + server.info.uri) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/views/authenticated.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Signed in!

4 |

5 | Avatar 6 |

7 |

8 | Hi {{name}}, great to see you! 9 |

10 |

11 | Logout 12 |

13 |
14 |
15 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Sign in with GitHub

5 |

6 | Hi Buddy, sign in using GitHub authentication. 7 |

8 |

9 | 10 |   11 | Authenticate with GitHub 12 | 13 |

14 |
15 |
16 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-github/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | {{{ content }}} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/authentication/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hoek = require('hoek') 4 | 5 | exports.register = function (server, options, next) { 6 | // declare dependency to hapi-auth-cookie and bell 7 | server.register([ 8 | { 9 | register: require('hapi-auth-cookie') 10 | }, 11 | { 12 | register: require('bell') 13 | } 14 | ], err => { 15 | Hoek.assert(!err, 'Cannot register authentication plugin') 16 | 17 | /** 18 | * Register session based auth strategy to store 19 | * credentials received from GitLab and keep 20 | * the user logged in 21 | */ 22 | server.auth.strategy('session', 'cookie', { 23 | password: 'ThisIsASecretPasswordForTheAuthCookie', 24 | redirectTo: '/', 25 | isSecure: process.env.NODE_ENV === 'production' 26 | }) 27 | 28 | /** 29 | * Register 'gitlab' authentication strategy 30 | */ 31 | server.auth.strategy('gitlab', 'bell', { 32 | provider: 'gitlab', 33 | password: 'ThisIsASecretCookiePasswordForGitLab', 34 | clientId: '281d2b423e8715a8d8bd1d2c60ab7b3218feb6346a89913bfe4a868a837cc5d8', 35 | clientSecret: '47c184bcd3e13096e1500d9f7c16d58b19ba6a4e55939cd1a8e33472e2d268e4', 36 | isSecure: process.env.NODE_ENV === 'production' 37 | }) 38 | 39 | server.log('info', 'Plugin registered: bell authentication with strategy »gitlab«') 40 | 41 | next() 42 | }) 43 | } 44 | 45 | exports.register.attributes = { 46 | name: 'authentication', 47 | version: '1.0.0' 48 | } 49 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/connect-with-gitlab/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = { 4 | index: { 5 | auth: { 6 | mode: 'try', 7 | strategy: 'session' 8 | }, 9 | plugins: { 10 | 'hapi-auth-cookie': { 11 | redirectTo: false 12 | } 13 | }, 14 | handler: function (request, reply) { 15 | if (request.auth.isAuthenticated) { 16 | return reply.view('authenticated', request.auth.credentials) 17 | } 18 | 19 | reply.view('index') 20 | } 21 | }, 22 | 23 | /** 24 | * used to authenticate 25 | */ 26 | connect: { 27 | auth: 'gitlab', 28 | handler: function (request, reply) { 29 | if (request.auth.isAuthenticated) { 30 | const user = request.auth.credentials.profile 31 | const data = { 32 | name: user.name, 33 | username: user.username, 34 | avatar: user.avatar_url 35 | } 36 | 37 | request.cookieAuth.set(data) 38 | return reply.view('authenticated', data) 39 | } 40 | 41 | reply.view('index', { 42 | error: 'There was an issue with GitLab authentication.' 43 | }).code(400) 44 | } 45 | }, 46 | 47 | logout: { 48 | auth: 'session', 49 | handler: function (request, reply) { 50 | request.cookieAuth.clear() 51 | reply.view('index') 52 | } 53 | } 54 | } 55 | 56 | module.exports = Handler 57 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/connect-with-gitlab/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.dependency([ 'authentication', 'vision' ]) 7 | 8 | server.route(Routes) 9 | server.log('info', 'Plugin registered: connect to GitLab') 10 | 11 | next() 12 | } 13 | 14 | exports.register.attributes = { 15 | name: 'connect-to-gitlab', 16 | version: '1.0.0' 17 | } 18 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/connect-with-gitlab/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: 'GET', 13 | path: '/auth/gitlab', 14 | config: Handler.connect 15 | }, 16 | { 17 | method: 'GET', 18 | path: '/logout', 19 | config: Handler.logout 20 | } 21 | ] 22 | 23 | module.exports = Routes 24 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('./authentication') 18 | }, 19 | { 20 | register: require('vision') 21 | }, 22 | { 23 | register: require('./connect-with-gitlab') 24 | } 25 | ], function (err) { 26 | if (err) { 27 | throw err 28 | } 29 | 30 | server.views({ 31 | engines: { 32 | html: require('handlebars') 33 | }, 34 | path: __dirname + '/views', 35 | layout: 'layout' 36 | }) 37 | 38 | // start your server 39 | server.start(function (err) { 40 | 41 | if (err) { 42 | throw err 43 | } 44 | 45 | console.log('Server running at: ' + server.info.uri) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/views/authenticated.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Signed in!

4 |

5 | Avatar 6 |

7 |

8 | Hi {{name}}, great to see you! 9 |

10 |

11 | Logout 12 |

13 |
14 |
15 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Sign in with GitLab

5 |

6 | Hi Buddy, sign in using GitLab authentication. They’re awesome! 7 |

8 |

9 | 10 |   11 | Authenticate with GitLab 12 | 13 |

14 |
15 |
16 | -------------------------------------------------------------------------------- /hapi-16/authenticate-with-gitlab/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | {{{ content }}} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /hapi-16/basic-auth/basic-routes.js: -------------------------------------------------------------------------------- 1 | var routes = [ 2 | { 3 | method: 'GET', 4 | path: '/', 5 | handler: function (request, reply) { 6 | var data = { 7 | message: 'Check the route that requires auth at /basic' 8 | } 9 | 10 | reply.view('index', data) 11 | } 12 | }, 13 | { 14 | method: 'GET', 15 | path: '/basic', 16 | config: { 17 | auth: 'basic', 18 | handler: function (request, reply) { 19 | reply.view('success') 20 | } 21 | } 22 | } 23 | ] 24 | 25 | module.exports = routes -------------------------------------------------------------------------------- /hapi-16/basic-auth/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | var Bcrypt = require('bcrypt') 4 | var Vision = require('vision') 5 | var Handlebars = require('handlebars') 6 | var BasicAuth = require('hapi-auth-basic') 7 | 8 | // create new server instance 9 | var server = new Hapi.Server() 10 | 11 | // add server’s connection information 12 | server.connection({ 13 | host: 'localhost', 14 | port: 3000 15 | }) 16 | 17 | // register plugins to server instance 18 | server.register([ 19 | { 20 | register: Vision 21 | }, 22 | { 23 | register: Good, 24 | options: { 25 | ops: { 26 | interval: 10000 27 | }, 28 | reporters: { 29 | console: [ 30 | { 31 | module: 'good-squeeze', 32 | name: 'Squeeze', 33 | args: [ { log: '*', response: '*', request: '*' } ] 34 | }, 35 | { 36 | module: 'good-console' 37 | }, 38 | 'stdout' 39 | ] 40 | } 41 | } 42 | }, 43 | { 44 | register: BasicAuth 45 | } 46 | ], function (err) { 47 | if (err) { 48 | server.log('error', 'failed to install plugins') 49 | 50 | throw err 51 | } 52 | 53 | server.log('info', 'Plugins registered') 54 | 55 | /** 56 | * view configuration 57 | */ 58 | server.views({ 59 | engines: { 60 | html: Handlebars 61 | }, 62 | path: __dirname + '/views', 63 | layout: true 64 | }) 65 | server.log('info', 'View configuration completed') 66 | 67 | // hardcoded users object … just for illustration purposes 68 | var users = { 69 | future: { 70 | username: 'future', 71 | password: '$2a$04$YPy8WdAtWswed8b9MfKixebJkVUhEZxQCrExQaxzhcdR2xMmpSJiG', // 'studio' 72 | name: 'Future Studio', 73 | id: '1' 74 | } 75 | } 76 | 77 | // validation function used for hapi-auth-basic 78 | var basicValidation = function (request, username, password, callback) { 79 | var user = users[ username ] 80 | 81 | if (!user) { 82 | return callback(null, false) 83 | } 84 | 85 | Bcrypt.compare(password, user.password, function (err, isValid) { 86 | server.log('info', 'user authentication successful') 87 | callback(err, isValid, { id: user.id, name: user.name }) 88 | }) 89 | } 90 | 91 | server.auth.strategy('basic', 'basic', { validateFunc: basicValidation }) 92 | server.log('info', 'Registered auth strategy: basic auth') 93 | 94 | var routes = require('./basic-routes') 95 | server.route(routes) 96 | server.log('info', 'Routes registered') 97 | 98 | 99 | 100 | // start your server after plugin registration 101 | server.start(function (err) { 102 | if (err) { 103 | server.log('error', 'failed to start server') 104 | server.log('error', err) 105 | 106 | throw err 107 | } 108 | 109 | server.log('info', 'Server running at: ' + server.info.uri) 110 | }) 111 | }) 112 | -------------------------------------------------------------------------------- /hapi-16/basic-auth/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |

Hapi Basic Authentication

3 | authenticate 4 | 8 |
-------------------------------------------------------------------------------- /hapi-16/basic-auth/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hapi — Basic Authentication 5 | 6 | 7 | 8 | {{{ content }}} 9 | 10 | 11 | -------------------------------------------------------------------------------- /hapi-16/basic-auth/views/success.html: -------------------------------------------------------------------------------- 1 |
2 |

Yeah, you made it! This view is only visible after successful authentication.

3 |
-------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/authentication/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.register = function (server, options, next) { 4 | // declare dependency to hapi-auth-cookie and bell 5 | server.dependency([ 'hapi-auth-cookie', 'bell' ]) 6 | 7 | /** 8 | * Register session based auth strategy to store 9 | * credentials received from GitHub and keep 10 | * the user logged in 11 | */ 12 | server.auth.strategy('session', 'cookie', { 13 | password: 'ThisIsASecretPasswordForTheAuthCookie', 14 | redirectTo: '/', 15 | isSecure: process.env.NODE_ENV === 'production' 16 | }) 17 | 18 | /** 19 | * Register 'digitalocean' authentication strategy 20 | */ 21 | const doUrl = 'https://cloud.digitalocean.com/v1/oauth' 22 | const doUserUrl = 'https://api.digitalocean.com/v2/account' 23 | 24 | server.auth.strategy('digitalocean', 'bell', { 25 | //provider: 'github', // <-- instead of this, we do this -> 26 | provider: { 27 | protocol: 'oauth2', 28 | auth: doUrl + '/authorize', 29 | token: doUrl + '/token', 30 | scope: [ 'read write' ], 31 | profile: function (credentials, params, get, callback) { 32 | get(doUserUrl, null, (profile) => { 33 | const account = profile.account 34 | 35 | credentials.profile = { 36 | email: account.email, 37 | status: account.status, 38 | dropletLimit: account.droplet_limit, 39 | raw: account 40 | } 41 | 42 | return callback() 43 | }) 44 | } 45 | }, 46 | password: 'ThisIsASecretCookiePasswordForDigitalOcean', 47 | clientId: '499d5ba6f00cdc7f4d2c9213c837b5f219a647e377352187087654d2e5804937', 48 | clientSecret: '1f05d6ad0cbcc74f064300bb3bb8344b93a4d48808439d7cce6dcc79a54de068', 49 | isSecure: process.env.NODE_ENV === 'production' 50 | }) 51 | 52 | server.log('info', 'Plugin registered: bell authentication with strategy »digitalocean«') 53 | 54 | next() 55 | } 56 | 57 | exports.register.attributes = { 58 | name: 'authentication', 59 | version: '1.0.0' 60 | } 61 | -------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/connect-with-your-server/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = { 4 | index: { 5 | auth: { 6 | mode: 'try', 7 | strategy: 'session' 8 | }, 9 | plugins: { 10 | 'hapi-auth-cookie': { 11 | redirectTo: false 12 | } 13 | }, 14 | handler: function (request, reply) { 15 | if (request.auth.isAuthenticated) { 16 | return reply.view('authenticated', request.auth.credentials) 17 | } 18 | 19 | reply.view('index') 20 | } 21 | }, 22 | 23 | /** 24 | * used to authenticate 25 | */ 26 | connect: { 27 | auth: 'digitalocean', 28 | handler: function (request, reply) { 29 | if (request.auth.isAuthenticated) { 30 | const user = request.auth.credentials.profile 31 | const data = { 32 | email: user.email, 33 | } 34 | 35 | request.cookieAuth.set(data) 36 | return reply.view('authenticated', data) 37 | } 38 | 39 | reply.view('index', { 40 | error: 'There was an issue with the GitHub authentication.' 41 | }).code(400) 42 | } 43 | }, 44 | 45 | logout: { 46 | auth: 'session', 47 | handler: function (request, reply) { 48 | request.cookieAuth.clear() 49 | reply.view('index') 50 | } 51 | } 52 | } 53 | 54 | module.exports = Handler 55 | -------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/connect-with-your-server/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.dependency([ 'authentication', 'vision' ]) 7 | 8 | server.route(Routes) 9 | server.log('info', 'Plugin registered: connect to GitHub') 10 | 11 | next() 12 | } 13 | 14 | exports.register.attributes = { 15 | name: 'connect-to-custom-auth-provider', 16 | version: '1.0.0' 17 | } 18 | -------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/connect-with-your-server/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: 'GET', 13 | path: '/auth/digitalocean', 14 | config: Handler.connect 15 | }, 16 | { 17 | method: 'GET', 18 | path: '/logout', 19 | config: Handler.logout 20 | } 21 | ] 22 | 23 | module.exports = Routes 24 | -------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const server = new Hapi.Server() 5 | 6 | // add server’s connection information 7 | server.connection({ 8 | host: 'localhost', 9 | port: 3000 10 | }) 11 | 12 | // register plugins to server instance 13 | server.register([ 14 | { 15 | register: require('hapi-auth-cookie') 16 | }, 17 | { 18 | register: require('bell') 19 | }, 20 | { 21 | register: require('./authentication') 22 | }, 23 | { 24 | register: require('vision') 25 | }, 26 | { 27 | register: require('./connect-with-your-server') 28 | } 29 | ], function (err) { 30 | if (err) { 31 | throw err 32 | } 33 | 34 | server.views({ 35 | engines: { 36 | html: require('handlebars') 37 | }, 38 | path: __dirname + '/views', 39 | layout: 'layout' 40 | }) 41 | 42 | // start your server 43 | server.start(function (err) { 44 | 45 | if (err) { 46 | throw err 47 | } 48 | 49 | console.log('Server running at: ' + server.info.uri) 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/views/authenticated.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Signed in!

5 | 6 | {{#if avatar}} 7 |

8 | Avatar 9 |

10 | {{/if}} 11 | 12 |

13 | Hi {{email}}, great to see you! 14 |

15 |

16 | Logout 17 |

18 |
19 |
20 | -------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Sign in with OAuth

5 | {{!-- 6 |

7 | Hi Buddy, authenticate with any OAuth Provider. 8 |

9 |

10 | 11 |   12 | Authenticate with your Provider 13 | 14 |

15 | 16 |
17 | 18 | --}} 19 |

20 | To illustrate the hapi configuration for a custom OAuth provider, 21 | let’s go with DigitalOcean and manually do the setup. You can apply 22 | the configuration to your provider. 23 |

24 |

25 | 26 |   27 | Authenticate with DigitalOcean 28 | 29 |

30 | {{!

31 | Sorry DigitalOcean for the wrong logo, Font Awesome doesn’t have 32 | the correct one yet :-/ 33 |

34 | }} 35 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /hapi-16/bell-custom-oauth/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | {{{ content }}} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /hapi-16/cookie-auth/cookie-routes.js: -------------------------------------------------------------------------------- 1 | var Boom = require('boom') 2 | var Bcrypt = require('bcrypt') 3 | var Users = require('./users-db') 4 | 5 | var routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: { 10 | auth: { 11 | mode: 'try', 12 | strategy: 'session' 13 | }, 14 | plugins: { 15 | 'hapi-auth-cookie': { 16 | redirectTo: false 17 | } 18 | }, 19 | handler: function (request, reply) { 20 | if (request.auth.isAuthenticated) { 21 | return reply.view('profile') 22 | } 23 | 24 | reply.view('index') 25 | } 26 | } 27 | }, 28 | { 29 | method: 'POST', 30 | path: '/', 31 | config: { 32 | auth: { 33 | mode: 'try' 34 | }, 35 | plugins: { 36 | 'hapi-auth-cookie': { 37 | redirectTo: false 38 | } 39 | }, 40 | handler: function (request, reply) { 41 | if (request.auth.isAuthenticated) { 42 | return reply.view('Profile') 43 | } 44 | 45 | var username = request.payload.username 46 | var user = Users[ username ] 47 | 48 | if (!user) { 49 | return reply(Boom.notFound('No user registered with given credentials')) 50 | } 51 | 52 | var password = request.payload.password 53 | 54 | return Bcrypt.compare(password, user.password, function (err, isValid) { 55 | if (isValid) { 56 | request.server.log('info', 'user authentication successful') 57 | request.cookieAuth.set(user); 58 | return reply.view('profile') 59 | } 60 | 61 | return reply.view('index') 62 | }) 63 | } 64 | } 65 | }, 66 | { 67 | method: 'GET', 68 | path: '/logout', 69 | config: { 70 | auth: 'session', 71 | handler: function (request, reply) { 72 | request.cookieAuth.clear(); 73 | reply.view('index') 74 | } 75 | } 76 | } 77 | ] 78 | 79 | module.exports = routes -------------------------------------------------------------------------------- /hapi-16/cookie-auth/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | var Vision = require('vision') 4 | var Users = require('./users-db') 5 | var Handlebars = require('handlebars') 6 | var CookieAuth = require('hapi-auth-cookie') 7 | 8 | // create new server instance 9 | var server = new Hapi.Server() 10 | 11 | // add server’s connection information 12 | server.connection({ 13 | host: 'localhost', 14 | port: 3000 15 | }) 16 | 17 | // register plugins to server instance 18 | server.register([ 19 | { 20 | register: Vision 21 | }, 22 | { 23 | register: Good, 24 | options: { 25 | ops: { 26 | interval: 10000 27 | }, 28 | reporters: { 29 | console: [ 30 | { 31 | module: 'good-squeeze', 32 | name: 'Squeeze', 33 | args: [ { log: '*', response: '*', request: '*' } ] 34 | }, 35 | { 36 | module: 'good-console' 37 | }, 38 | 'stdout' 39 | ] 40 | } 41 | } 42 | }, 43 | { 44 | register: CookieAuth 45 | } 46 | ], function (err) { 47 | if (err) { 48 | server.log('error', 'failed to install plugins') 49 | 50 | throw err 51 | } 52 | 53 | server.log('info', 'Plugins registered') 54 | 55 | /** 56 | * view configuration 57 | */ 58 | server.views({ 59 | engines: { 60 | html: Handlebars 61 | }, 62 | path: __dirname + '/views', 63 | layout: true 64 | }) 65 | server.log('info', 'View configuration completed') 66 | 67 | // validation function used for hapi-auth-cookie: optional and checks if the user is still existing 68 | var validation = function (request, session, callback) { 69 | var username = session.username 70 | var user = Users[ username ] 71 | 72 | if (!user) { 73 | return callback(null, false) 74 | } 75 | 76 | server.log('info', 'user authenticated') 77 | callback(err, true, user) 78 | } 79 | 80 | server.auth.strategy('session', 'cookie', true, { 81 | password: 'm!*"2/),p4:xDs%KEgVr7;e#85Ah^WYC', 82 | cookie: 'future-studio-hapi-tutorials-cookie-auth-example', 83 | redirectTo: '/', 84 | isSecure: false, 85 | validateFunc: validation 86 | }) 87 | 88 | server.log('info', 'Registered auth strategy: cookie auth') 89 | 90 | var routes = require('./cookie-routes') 91 | server.route(routes) 92 | server.log('info', 'Routes registered') 93 | 94 | // start your server after plugin registration 95 | server.start(function (err) { 96 | if (err) { 97 | server.log('error', 'failed to start server') 98 | server.log('error', err) 99 | 100 | throw err 101 | } 102 | 103 | server.log('info', 'Server running at: ' + server.info.uri) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /hapi-16/cookie-auth/users-db.js: -------------------------------------------------------------------------------- 1 | // hardcoded users object … just for illustration purposes 2 | var users = { 3 | future: { 4 | username: 'future', 5 | password: '$2a$04$YPy8WdAtWswed8b9MfKixebJkVUhEZxQCrExQaxzhcdR2xMmpSJiG', // 'studio' 6 | name: 'Future Studio', 7 | id: '1' 8 | } 9 | } 10 | 11 | module.exports = users -------------------------------------------------------------------------------- /hapi-16/cookie-auth/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |

Hapi Cookie Authentication

3 |

4 | Use the following credentials to log in. 5 |

6 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
-------------------------------------------------------------------------------- /hapi-16/cookie-auth/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hapi — Basic Authentication 5 | 6 | 7 | 8 | {{{ content }}} 9 | 10 | 11 | -------------------------------------------------------------------------------- /hapi-16/cookie-auth/views/profile.html: -------------------------------------------------------------------------------- 1 |
2 |

Your Profile

3 |

4 | logout 5 |

6 |
-------------------------------------------------------------------------------- /hapi-16/cookies-store-and-read/base-route.js: -------------------------------------------------------------------------------- 1 | var util = require('util') 2 | 3 | var baseRoutes = { 4 | register: function (server, options, next) { 5 | server.state('session', { 6 | ttl: 1000 * 60 * 60 * 24, 7 | encoding: 'base64json' 8 | }) 9 | 10 | server.state('email', { 11 | ttl: 1000 * 60 * 60 * 24 * 7 12 | }) 13 | 14 | var routes = [ 15 | { 16 | method: 'GET', 17 | path: '/', 18 | config: { 19 | handler: function (request, reply) { 20 | var email = request.state.email 21 | if (!email) { 22 | email = 'info@futurestud.io' 23 | } 24 | 25 | var session = request.state.session 26 | if (!session) { 27 | session = { 28 | username: 'futurestudio', 29 | firstvisit: false 30 | } 31 | } 32 | 33 | cookie.lastVisit = Date.now() 34 | 35 | return reply('Hello Future Studio') 36 | .state('session', session) 37 | .state('email', email) 38 | } 39 | } 40 | } 41 | ] 42 | 43 | // add defined routes to hapi 44 | server.route(routes) 45 | next() 46 | } 47 | } 48 | 49 | baseRoutes.register.attributes = { 50 | name: 'response-status', 51 | version: '1.0.0' 52 | } 53 | 54 | module.exports = baseRoutes 55 | -------------------------------------------------------------------------------- /hapi-16/cookies-store-and-read/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: Good, 17 | options: { 18 | ops: { 19 | interval: 10000 20 | }, 21 | reporters: { 22 | console: [ 23 | { 24 | module: 'good-squeeze', 25 | name: 'Squeeze', 26 | args: [ { log: '*', response: '*', request: '*' } ] 27 | }, 28 | { 29 | module: 'good-console' 30 | }, 31 | 'stdout' 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | register: require('./base-route') 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/default-auth-strategy/routes.js: -------------------------------------------------------------------------------- 1 | var routes = [ 2 | { 3 | method: 'GET', 4 | path: '/', 5 | config: { 6 | handler: function (request, reply) { 7 | if (request.auth.isAuthenticated) { 8 | return reply('Authenticated') 9 | } 10 | 11 | reply('Not Authenticated') 12 | } 13 | } 14 | }, 15 | { 16 | method: 'GET', 17 | path: '/not-authenticated', 18 | config: { 19 | handler: function (request, reply) { 20 | if (request.auth.isAuthenticated) { 21 | return reply('Authenticated') 22 | } 23 | 24 | reply('Not Authenticated') 25 | } 26 | } 27 | } 28 | ] 29 | 30 | module.exports = routes -------------------------------------------------------------------------------- /hapi-16/default-auth-strategy/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | var Vision = require('vision') 4 | var Bcrypt = require('bcrypt') 5 | var Users = require('./users-db') 6 | var BasicAuth = require('hapi-auth-basic') 7 | 8 | // create new server instance 9 | var server = new Hapi.Server() 10 | 11 | // add server’s connection information 12 | server.connection({ 13 | host: 'localhost', 14 | port: 3000 15 | }) 16 | 17 | // register plugins to server instance 18 | server.register([ 19 | { 20 | register: Good, 21 | options: { 22 | ops: { 23 | interval: 10000 24 | }, 25 | reporters: { 26 | console: [ 27 | { 28 | module: 'good-squeeze', 29 | name: 'Squeeze', 30 | args: [ { log: '*', response: '*', request: '*' } ] 31 | }, 32 | { 33 | module: 'good-console' 34 | }, 35 | 'stdout' 36 | ] 37 | } 38 | } 39 | }, 40 | { 41 | register: BasicAuth 42 | } 43 | ], function (err) { 44 | if (err) { 45 | server.log('error', 'failed to install plugins') 46 | 47 | throw err 48 | } 49 | 50 | server.log('info', 'Plugins registered') 51 | 52 | var basicValidation = function (request, username, password, callback) { 53 | var user = Users[ username ] 54 | 55 | if (!user) { 56 | return callback(null, false) 57 | } 58 | 59 | Bcrypt.compare(password, user.password, function (err, isValid) { 60 | server.log('info', 'user authentication successful') 61 | callback(err, isValid, user) 62 | }) 63 | } 64 | 65 | // Create auth strategy: 66 | // 1. without setting it as default 67 | server.auth.strategy('basic', 'basic', { validateFunc: basicValidation }) 68 | // set default auth strategy separately 69 | // all routes added afterwards will follow the default, required auth strategy 70 | server.auth.default('basic') 71 | 72 | // 2. set it as default 73 | // all routes will automatically require and follow the default strategy 74 | // server.auth.strategy('basic', 'basic', true, { validateFunc: basicValidation }) 75 | 76 | server.log('info', 'Registered auth strategy: basic auth') 77 | 78 | var routes = require('./routes') 79 | server.route(routes) 80 | server.log('info', 'Routes registered') 81 | 82 | // start your server after plugin registration 83 | server.start(function (err) { 84 | if (err) { 85 | server.log('error', 'failed to start server') 86 | server.log('error', err) 87 | 88 | throw err 89 | } 90 | 91 | server.log('info', 'Server running at: ' + server.info.uri) 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /hapi-16/default-auth-strategy/users-db.js: -------------------------------------------------------------------------------- 1 | // hardcoded users object … just for illustration purposes 2 | var users = { 3 | future: { 4 | username: 'future', 5 | password: '$2a$04$YPy8WdAtWswed8b9MfKixebJkVUhEZxQCrExQaxzhcdR2xMmpSJiG', // 'studio' 6 | name: 'Future Studio', 7 | id: '1' 8 | } 9 | } 10 | 11 | module.exports = users -------------------------------------------------------------------------------- /hapi-16/different-default-handlebars-layouts/index/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = { 4 | index: { 5 | handler: function (request, reply) { 6 | reply.view('index') 7 | } 8 | }, 9 | 10 | second: { 11 | handler: function (request, reply) { 12 | reply.view('index', null, { layout: 'second-layout' }) 13 | } 14 | } 15 | } 16 | 17 | module.exports = Handler 18 | -------------------------------------------------------------------------------- /hapi-16/different-default-handlebars-layouts/index/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.dependency([ 'vision' ]) 7 | 8 | server.route(Routes) 9 | server.log('info', 'Plugin registered: use Vue.js with Handlebars in hapi') 10 | 11 | next() 12 | } 13 | 14 | exports.register.attributes = { 15 | name: 'vue-and-handlebars', 16 | version: '1.0.0' 17 | } 18 | -------------------------------------------------------------------------------- /hapi-16/different-default-handlebars-layouts/index/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: 'GET', 13 | path: '/second', 14 | config: Handler.second 15 | } 16 | ] 17 | 18 | module.exports = Routes 19 | -------------------------------------------------------------------------------- /hapi-16/different-default-handlebars-layouts/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const Path = require('path') 5 | 6 | // create new server instance 7 | const server = new Hapi.Server() 8 | 9 | // add server’s connection information 10 | server.connection({ 11 | host: 'localhost', 12 | port: 3000 13 | }) 14 | 15 | // register plugins to server instance 16 | server.register([ 17 | { 18 | register: require('vision') 19 | }, 20 | { 21 | register: require('./index') 22 | } 23 | ], function (err) { 24 | if (err) { 25 | throw err 26 | } 27 | 28 | server.views({ 29 | engines: { 30 | html: require('handlebars') 31 | }, 32 | layout: 'my-layout', 33 | path: Path.resolve('views') 34 | }) 35 | 36 | // start your server 37 | server.start(function (err) { 38 | if (err) { 39 | throw err 40 | } 41 | 42 | console.log('Server running at: ' + server.info.uri) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /hapi-16/different-default-handlebars-layouts/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Multiple Handlebars Layouts with hapi

5 |

6 | First Layout 7 | Second Layout 8 |

9 |
10 |
11 | 12 | 13 | 22 | -------------------------------------------------------------------------------- /hapi-16/different-default-handlebars-layouts/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Multiple Handlebars Layouts 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 |   18 | 19 |
20 |
21 | 22 | {{{ content }}} 23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /hapi-16/different-default-handlebars-layouts/views/second-layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Vue.js and Handlebars in hapi 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

16 | Second Layout, without Fontawesome Integration 17 |

18 |
19 |
20 | 21 | {{{ content }}} 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /hapi-16/extend-hapi-with-plugins/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // add “hello world” route 14 | server.route({ 15 | method: 'GET', 16 | path: '/', 17 | handler: function (request, reply) { 18 | reply('Hello Future Studio!') 19 | } 20 | }) 21 | 22 | // register plugins to server instance 23 | server.register({ 24 | register: Good, 25 | options: { 26 | ops: { 27 | interval: 10000 28 | }, 29 | reporters: { 30 | console: [ 31 | { 32 | module: 'good-squeeze', 33 | name: 'Squeeze', 34 | args: [ { log: '*', response: '*', request: '*' } ] 35 | }, 36 | { 37 | module: 'good-console' 38 | }, 39 | 'stdout' 40 | ] 41 | } 42 | } 43 | }) 44 | 45 | // start your server 46 | server.start(function (err) { 47 | if (err) { 48 | throw err 49 | } 50 | 51 | server.log('info', 'Server running at: ' + server.info.uri) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/getting-started/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | 3 | // create new server instance 4 | var server = new Hapi.Server() 5 | 6 | // add server’s connection information 7 | server.connection({ 8 | host: 'localhost', 9 | port: 3000 10 | }) 11 | 12 | // add “hello world” route 13 | server.route({ 14 | method: 'GET', 15 | path: '/', 16 | handler: function (request, reply) { 17 | reply('Hello Future Studio!') 18 | } 19 | }) 20 | 21 | // start your server 22 | server.start(function (err) { 23 | if (err) { 24 | throw err 25 | } 26 | 27 | console.log('Server running at: ' + server.info.uri) 28 | }) 29 | -------------------------------------------------------------------------------- /hapi-16/hapi-vue-ssr-basic/base/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Fs = require('fs') 4 | const Vue = require('vue') 5 | const Boom = require('boom') 6 | const Path = require('path') 7 | 8 | // initialize Renderer with default template layout 9 | const LayoutPath = Path.resolve(__dirname, '..', 'views', 'layout.html') 10 | const Renderer = require('vue-server-renderer').createRenderer({ 11 | template: Fs.readFileSync(LayoutPath, 'utf-8'), 12 | data: { 13 | title: 'Welcome to hapi-vue-ssr' 14 | } 15 | }) 16 | 17 | function renderAndReply (template, context, reply) { 18 | const TemplatePath = Path.resolve(__dirname, '..', 'views', `${template}.html`) 19 | const app = new Vue({ 20 | data: context, 21 | template: Fs.readFileSync(TemplatePath, 'utf-8') 22 | }) 23 | 24 | return Renderer.renderToString(app, (err, html) => { 25 | if (err) { 26 | console.log(err) 27 | return reply(Boom.boomify(err, { statusCode: 500 })) 28 | } 29 | 30 | return reply(html) 31 | }) 32 | } 33 | 34 | const Handler = { 35 | index: { 36 | handler: (request, reply) => { 37 | renderAndReply('index', null, reply) 38 | } 39 | }, 40 | 41 | missing: { 42 | handler: (request, reply) => { 43 | renderAndReply('about', { url: request.url.path }, reply) 44 | } 45 | } 46 | } 47 | 48 | module.exports = Handler 49 | -------------------------------------------------------------------------------- /hapi-16/hapi-vue-ssr-basic/base/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.route(Routes) 7 | server.log('info', 'Plugin registered: 404 handler') 8 | 9 | next() 10 | } 11 | 12 | exports.register.attributes = { 13 | name: '404-handler', 14 | version: '1.0.0' 15 | } 16 | -------------------------------------------------------------------------------- /hapi-16/hapi-vue-ssr-basic/base/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: [ 'GET', 'POST' ], 13 | path: '/{path*}', 14 | config: Handler.missing 15 | } 16 | ] 17 | 18 | module.exports = Routes 19 | -------------------------------------------------------------------------------- /hapi-16/hapi-vue-ssr-basic/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('inert') 18 | }, 19 | { 20 | register: require('./base') 21 | } 22 | ]).then(() => { 23 | server.start() 24 | }).then(() => { 25 | console.log('Server running at: ' + server.info.uri) 26 | }).catch(err => { 27 | throw err 28 | }) 29 | -------------------------------------------------------------------------------- /hapi-16/hapi-vue-ssr-basic/views/about.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Hey there 😘

5 |

6 | Future Studio is helping 5,000+ users daily to solve 7 | Android and Node.js problems with 350+ written tutorials 8 | and videos. We’re on a mission to provide new in-depth 9 | content every week. 10 |

11 | 12 |
13 | 14 |

15 | Take me back to the 16 | startpage 17 |

18 | 19 |
20 | 21 |

22 | You’re here: {{ url }} 23 |

24 |
25 |
26 | -------------------------------------------------------------------------------- /hapi-16/hapi-vue-ssr-basic/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Hello!

5 | 6 |

7 | This page is rendered with Vue.js on the server 🤘😃 8 |

9 |

10 | Go anywhere, you’ll see the another SSR page 11 |

12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /hapi-16/hapi-vue-ssr-basic/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | hapi & Vue SSR 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /hapi-16/ignore-trailing-slash-on-paths/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const baseRoutes = { 4 | register: function (server, options, next) { 5 | // add defined route to hapi server 6 | server.route([ 7 | { 8 | method: 'GET', 9 | path: '/', 10 | handler: function (request, reply) { 11 | reply('Did the work :)') 12 | } 13 | }, 14 | { 15 | method: 'GET', 16 | path: '/slash', 17 | handler: function (request, reply) { 18 | reply('Called the /slash or /slash/ route') 19 | } 20 | }, 21 | { 22 | method: 'GET', 23 | path: '/slash/{name}', 24 | handler: function (request, reply) { 25 | reply('Called route with slash at the end: ' + request.params.name) 26 | } 27 | } 28 | ]) 29 | 30 | next() 31 | } 32 | } 33 | 34 | baseRoutes.register.attributes = { 35 | name: 'base-routes', 36 | version: '1.0.0' 37 | } 38 | 39 | module.exports = baseRoutes -------------------------------------------------------------------------------- /hapi-16/ignore-trailing-slash-on-paths/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000, 11 | router: { 12 | stripTrailingSlash: true 13 | } 14 | }) 15 | 16 | // register plugins to server instance 17 | server.register([ 18 | { 19 | register: Good, 20 | options: { 21 | reporters: { 22 | console: [ 23 | { module: 'good-squeeze', name: 'Squeeze', args: [ { log: '*', response: '*', request: '*' } ] }, 24 | { module: 'good-console' }, 25 | 'stdout' 26 | ] 27 | } 28 | } 29 | }, 30 | { 31 | register: require('./base-route') 32 | } 33 | ], function (err) { 34 | if (err) { 35 | throw err 36 | } 37 | 38 | server.log('info', 'Registered plugins') 39 | 40 | // start your server after plugin registration 41 | server.start(function (err) { 42 | if (err) { 43 | throw err 44 | } 45 | 46 | server.log('info', 'Server running at: ' + server.info.uri) 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /hapi-16/multiple-auth-strategies-for-routes/routes.js: -------------------------------------------------------------------------------- 1 | var Boom = require('boom') 2 | var Bcrypt = require('bcrypt') 3 | var Users = require('./users-db') 4 | 5 | var routes = [ 6 | { 7 | method: 'GET', 8 | path: '/profile', 9 | config: { 10 | auth: { 11 | strategies: ['simple', 'session'] 12 | }, 13 | handler: function (request, reply) { 14 | return reply.view('profile') 15 | } 16 | } 17 | }, 18 | { 19 | method: 'GET', 20 | path: '/', 21 | config: { 22 | auth: { 23 | mode: 'try', 24 | strategy: 'session' 25 | }, 26 | plugins: { 27 | 'hapi-auth-cookie': { 28 | redirectTo: false 29 | } 30 | }, 31 | handler: function (request, reply) { 32 | if (request.auth.isAuthenticated) { 33 | return reply.view('profile') 34 | } 35 | 36 | reply.view('index') 37 | } 38 | } 39 | }, 40 | { 41 | method: 'POST', 42 | path: '/', 43 | config: { 44 | // auth: 'session', 45 | auth: { 46 | mode: 'try' 47 | }, 48 | plugins: { 49 | 'hapi-auth-cookie': { 50 | redirectTo: false 51 | } 52 | }, 53 | handler: function (request, reply) { 54 | if (request.auth.isAuthenticated) { 55 | return reply.view('Profile') 56 | } 57 | 58 | var username = request.payload.username 59 | var user = Users[ username ] 60 | 61 | if (!user) { 62 | return reply(Boom.notFound('No user registered with given credentials')) 63 | } 64 | 65 | var password = request.payload.password 66 | 67 | return Bcrypt.compare(password, user.password, function (err, isValid) { 68 | if (isValid) { 69 | request.server.log('info', 'user authentication successful') 70 | request.cookieAuth.set(user); 71 | return reply.view('profile') 72 | } 73 | 74 | return reply.view('index') 75 | }) 76 | } 77 | } 78 | }, 79 | { 80 | method: 'GET', 81 | path: '/logout', 82 | config: { 83 | auth: 'session', 84 | handler: function (request, reply) { 85 | request.cookieAuth.clear(); 86 | reply.view('index') 87 | } 88 | } 89 | } 90 | ] 91 | 92 | module.exports = routes -------------------------------------------------------------------------------- /hapi-16/multiple-auth-strategies-for-routes/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | var Vision = require('vision') 4 | var Bcrypt = require('bcrypt') 5 | var Users = require('./users-db') 6 | var Handlebars = require('handlebars') 7 | var BasicAuth = require('hapi-auth-basic') 8 | var CookieAuth = require('hapi-auth-cookie') 9 | 10 | // create new server instance 11 | var server = new Hapi.Server() 12 | 13 | // add server’s connection information 14 | server.connection({ 15 | host: 'localhost', 16 | port: 3000 17 | }) 18 | 19 | // register plugins to server instance 20 | server.register([ Vision, BasicAuth, CookieAuth, 21 | { 22 | register: Good, 23 | options: { 24 | ops: { 25 | interval: 10000 26 | }, 27 | reporters: { 28 | console: [ 29 | { 30 | module: 'good-squeeze', 31 | name: 'Squeeze', 32 | args: [ { log: '*', response: '*', request: '*' } ] 33 | }, 34 | { 35 | module: 'good-console' 36 | }, 37 | 'stdout' 38 | ] 39 | } 40 | } 41 | } 42 | ], function (err) { 43 | if (err) { 44 | server.log('error', 'failed to install plugins') 45 | 46 | throw err 47 | } 48 | 49 | server.log('info', 'Plugins registered') 50 | 51 | /** 52 | * view configuration 53 | */ 54 | server.views({ 55 | engines: { 56 | html: Handlebars 57 | }, 58 | path: __dirname + '/views', 59 | layout: true 60 | }) 61 | server.log('info', 'View configuration completed') 62 | 63 | // validation function used for hapi-auth-basic 64 | var basicValidation = function (request, username, password, callback) { 65 | var user = Users[ username ] 66 | 67 | if (!user) { 68 | return callback(null, false) 69 | } 70 | 71 | Bcrypt.compare(password, user.password, function (err, isValid) { 72 | server.log('info', 'user authentication successful') 73 | callback(err, isValid, { id: user.id, name: user.name }) 74 | }) 75 | } 76 | 77 | server.auth.strategy('simple', 'basic', { validateFunc: basicValidation }) 78 | server.log('info', 'Registered auth strategy: basic auth') 79 | 80 | // validation function used for hapi-auth-cookie: optional and checks if the user is still existing 81 | var cookieValidation = function (request, session, callback) { 82 | var username = session.username 83 | var user = Users[ username ] 84 | 85 | if (!user) { 86 | return callback(null, false) 87 | } 88 | 89 | server.log('info', 'user authenticated') 90 | callback(err, true, user) 91 | } 92 | 93 | server.auth.strategy('session', 'cookie', { 94 | password: 'm!*"2/),p4:xDs%KEgVr7;e#85Ah^WYC', 95 | cookie: 'future-studio-hapi-tutorials-cookie-auth-example', 96 | redirectTo: false, 97 | isSecure: false, 98 | validateFunc: cookieValidation 99 | }) 100 | server.log('info', 'Registered auth strategy: cookie auth') 101 | 102 | // default auth strategy avoids server crash for routes that doesn’t specify auth config 103 | server.auth.default('simple') 104 | 105 | var routes = require('./routes') 106 | server.route(routes) 107 | server.log('info', 'Routes registered') 108 | 109 | // start your server after plugin registration 110 | server.start(function (err) { 111 | if (err) { 112 | server.log('error', 'failed to start server') 113 | server.log('error', err) 114 | 115 | throw err 116 | } 117 | 118 | server.log('info', 'Server running at: ' + server.info.uri) 119 | }) 120 | }) 121 | -------------------------------------------------------------------------------- /hapi-16/multiple-auth-strategies-for-routes/users-db.js: -------------------------------------------------------------------------------- 1 | // hardcoded users object … just for illustration purposes 2 | var users = { 3 | future: { 4 | username: 'future', 5 | password: '$2a$04$YPy8WdAtWswed8b9MfKixebJkVUhEZxQCrExQaxzhcdR2xMmpSJiG', // 'studio' 6 | name: 'Future Studio', 7 | id: '1' 8 | } 9 | } 10 | 11 | module.exports = users -------------------------------------------------------------------------------- /hapi-16/multiple-auth-strategies-for-routes/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |

Hapi Cookie Authentication

3 |

4 | Use the following credentials to log in. 5 |

6 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
-------------------------------------------------------------------------------- /hapi-16/multiple-auth-strategies-for-routes/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hapi — Basic Authentication 5 | 6 | 7 | 8 | {{{ content }}} 9 | 10 | 11 | -------------------------------------------------------------------------------- /hapi-16/multiple-auth-strategies-for-routes/views/profile.html: -------------------------------------------------------------------------------- 1 |
2 |

Your Profile

3 |

4 | logout 5 |

6 |
-------------------------------------------------------------------------------- /hapi-16/multiple-server-instances/backend-route.js: -------------------------------------------------------------------------------- 1 | var plugin = { 2 | register: function (server, options, next) { 3 | server.route({ 4 | method: 'GET', 5 | path: '/', 6 | handler: function (request, reply) { 7 | reply('Backend is ok') 8 | } 9 | }) 10 | 11 | next() 12 | } 13 | } 14 | 15 | plugin.register.attributes = { 16 | name: 'multiple-server-instances-backend-routes', 17 | version: '1.0.0' 18 | } 19 | 20 | module.exports = plugin 21 | -------------------------------------------------------------------------------- /hapi-16/multiple-server-instances/frontend-route.js: -------------------------------------------------------------------------------- 1 | var plugin = { 2 | register: function (server, options, next) { 3 | server.route({ 4 | method: 'GET', 5 | path: '/', 6 | handler: function (request, reply) { 7 | reply('Frontend is totally fine') 8 | } 9 | }) 10 | 11 | next() 12 | } 13 | } 14 | 15 | plugin.register.attributes = { 16 | name: 'multiple-server-instances-frontend-routes', 17 | version: '1.0.0' 18 | } 19 | 20 | module.exports = plugin 21 | -------------------------------------------------------------------------------- /hapi-16/multiple-server-instances/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var _ = require('lodash') 3 | var port = 3000 4 | 5 | // create new server instance 6 | var server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | var frontend = server.connection({ 10 | host: 'localhost', 11 | port: process.env.PORT || port, 12 | labels: 'frontend' 13 | }) 14 | 15 | frontend.register({ 16 | register: require('./frontend-route') 17 | }) 18 | 19 | 20 | // add another server connection 21 | var backend = server.connection({ 22 | host: 'localhost', 23 | port: process.env.PORT + 1 || port + 1, 24 | labels: 'backend' 25 | }) 26 | 27 | backend.register({ 28 | register: require('./backend-route') 29 | }) 30 | 31 | 32 | // start your server after plugin registration 33 | server.start(function (err) { 34 | if (err) { 35 | throw err 36 | } 37 | 38 | _.forEach(server.connections, function(connection) { 39 | console.log('Server started at: ' + connection.info.uri) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /hapi-16/optional-path-params/base-route.js: -------------------------------------------------------------------------------- 1 | var plugin = { 2 | register: function (server, options, next) { 3 | var routes = [ 4 | { 5 | method: 'GET', 6 | path: '/{param?}', 7 | handler: function (request, reply) { 8 | var params = request.params 9 | 10 | server.log('info', params) 11 | 12 | reply(params) 13 | } 14 | } 15 | ] 16 | 17 | // add defined routes to hapi 18 | server.route(routes) 19 | 20 | next() 21 | } 22 | } 23 | 24 | plugin.register.attributes = { 25 | name: 'optional-path-params', 26 | version: '1.0.0' 27 | } 28 | 29 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/optional-path-params/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-tutorials-hapi", 3 | "description": "Example code related to an extensive hapi series on Future Studio (https://futurestud.io)", 4 | "version": "1.0.0", 5 | "author": "Future Studio ", 6 | "bugs": "https://github.com/fs-opensource/nodejs-tutorials-hapi/issues", 7 | "contributors": [ 8 | { 9 | "name": "Marcus Poehls", 10 | "email": "marcus@futurestud.io" 11 | } 12 | ], 13 | "dependencies": { 14 | "bcrypt": "~1.0.3", 15 | "bell": "~8.8.0", 16 | "boom": "~5.2.0", 17 | "good": "~7.3.0", 18 | "good-console": "~6.4.0", 19 | "good-file": "~6.0.1", 20 | "good-squeeze": "~5.0.2", 21 | "handlebars": "~4.5.3", 22 | "hapi": "~16.6.2", 23 | "hapi-auth-basic": "~4.2.0", 24 | "hapi-auth-cookie": "~7.0.0", 25 | "hapi-dev-errors": "~1.3.2", 26 | "hoek": "~6.1.3", 27 | "inert": "~4.2.1", 28 | "joi": "~10.5.2", 29 | "lodash": "~4.17.4", 30 | "pug": "~2.0.0-rc.4", 31 | "vision": "~4.1.1", 32 | "vue": "~2.5.2", 33 | "vue-server-renderer": "~2.5.2", 34 | "when": "~3.7.8" 35 | }, 36 | "devDependencies": { 37 | "eslint": "~4.9.0", 38 | "code": "~4.1.0", 39 | "lab": "~14.3.1", 40 | "eslint-config-standard": "~10.2.1", 41 | "eslint-plugin-import": "~2.8.0", 42 | "eslint-plugin-node": "~5.2.0", 43 | "eslint-plugin-promise": "~3.6.0", 44 | "eslint-plugin-standard": "~3.0.1" 45 | }, 46 | "engines": { 47 | "node": ">=4.0.0" 48 | }, 49 | "homepage": "https://futurestud.io/tutorials/hapi-get-your-server-up-and-running", 50 | "keywords": [ 51 | "hapi", 52 | "node.js", 53 | "tutorials" 54 | ], 55 | "license": "MIT", 56 | "repository": "https://github.com/fs-opensource/nodejs-tutorials-hapi", 57 | "scripts": { 58 | "test": "echo \"Error: no test specified\" && exit 1" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /hapi-16/path-params-of-same-name/base-route.js: -------------------------------------------------------------------------------- 1 | var plugin = { 2 | register: function (server, options, next) { 3 | var routes = [ 4 | { 5 | method: 'GET', 6 | path: '/filter/{type}', 7 | handler: function (request, reply) { 8 | var params = request.params 9 | 10 | server.log('info', params) 11 | 12 | reply(params) 13 | } 14 | } 15 | ] 16 | 17 | // add defined routes to hapi 18 | server.route(routes) 19 | 20 | next() 21 | } 22 | } 23 | 24 | plugin.register.attributes = { 25 | name: 'path-params-optional-wildcard', 26 | version: '1.0.0' 27 | } 28 | 29 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/path-params-of-same-name/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/query-params/base-route.js: -------------------------------------------------------------------------------- 1 | var plugin = { 2 | register: function (server, options, next) { 3 | var routes = [ 4 | { 5 | method: 'GET', 6 | path: '/', 7 | handler: function (request, reply) { 8 | var params = request.query 9 | 10 | server.log('info', params) 11 | 12 | reply(params) 13 | } 14 | } 15 | ] 16 | 17 | // add defined routes to hapi 18 | server.route(routes) 19 | 20 | next() 21 | } 22 | } 23 | 24 | plugin.register.attributes = { 25 | name: 'query-param-routes', 26 | version: '1.0.0' 27 | } 28 | 29 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/query-params/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/authentication/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Users = require('../users-db') 4 | const Hoek = require('hoek') 5 | 6 | exports.register = function (server, options, next) { 7 | // declare dependency to hapi-auth-cookie and bell 8 | server.register([ 9 | { 10 | register: require('hapi-auth-cookie') 11 | } 12 | ], err => { 13 | Hoek.assert(!err, 'Cannot register authentication plugin') 14 | 15 | /** 16 | * Register session based auth strategy to store 17 | * and validate the session cookie received with 18 | * the user’s requests 19 | */ 20 | server.auth.strategy('session', 'cookie', { 21 | password: 'ThisIsASecretPasswordForTheAuthCookie', 22 | redirectTo: '/login', 23 | appendNext: true, // appends the current URL to the query param "next". Set to a string to use a different query param name 24 | isSecure: process.env.NODE_ENV === 'production', 25 | validateFunc: (request, session, callback) => { 26 | // validate the existing session 27 | // this simple example checks the “users db” for an entry 28 | const username = session.username 29 | const user = Users[ username ] 30 | 31 | if (!user) { 32 | return callback(null, false) 33 | } 34 | 35 | callback(err, true, user) 36 | } 37 | }) 38 | 39 | next() 40 | }) 41 | } 42 | 43 | exports.register.attributes = { 44 | name: 'authentication', 45 | version: '1.0.0' 46 | } 47 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/implementation/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Bcrypt = require('bcrypt') 4 | const Users = require('../users-db') 5 | 6 | const Handler = { 7 | index: { 8 | auth: { 9 | mode: 'try', 10 | strategy: 'session' 11 | }, 12 | plugins: { 13 | 'hapi-auth-cookie': { 14 | redirectTo: false 15 | } 16 | }, 17 | handler: function (request, reply) { 18 | reply.view('index') 19 | } 20 | }, 21 | 22 | showLogin: { 23 | auth: { 24 | mode: 'try', 25 | strategy: 'session' 26 | }, 27 | plugins: { 28 | 'hapi-auth-cookie': { 29 | redirectTo: false 30 | } 31 | }, 32 | handler: function (request, reply) { 33 | if (request.auth.isAuthenticated) { 34 | return reply.redirect(request.query.next) 35 | } 36 | 37 | reply.view('login') 38 | } 39 | }, 40 | 41 | login: { 42 | auth: { 43 | mode: 'try', 44 | strategy: 'session' 45 | }, 46 | plugins: { 47 | 'hapi-auth-cookie': { 48 | redirectTo: false 49 | } 50 | }, 51 | handler: (request, reply) => { 52 | if (request.auth.isAuthenticated) { 53 | return reply.redirect(request.query.next) 54 | } 55 | 56 | const username = request.payload.username 57 | const user = Users[ username ] 58 | 59 | if (!user) { 60 | // no user found with given username 61 | return reply.view('login', { 62 | username, 63 | errormessage: 'No user registered with given credentials' 64 | }).code(404) 65 | } 66 | 67 | const password = request.payload.password 68 | 69 | return Bcrypt.compare(password, user.password, (err, isValid) => { 70 | if (isValid) { 71 | request.cookieAuth.set(user) 72 | 73 | // check whether there’s a value for "next" query param 74 | // if not, define the default "/" 75 | const next = request.query.next ? request.query.next : '/' 76 | 77 | // redirect the user to the previous page 78 | return reply.redirect(next) 79 | } 80 | 81 | // given password doesn’t match the stored one 82 | return reply.view('login', { 83 | username, 84 | errormessage: 'No user registered with given credentials' 85 | }).code(404) 86 | }) 87 | } 88 | }, 89 | 90 | private: { 91 | auth: 'session', 92 | handler: function (request, reply) { 93 | reply.view('private') 94 | } 95 | }, 96 | 97 | profile: { 98 | auth: 'session', 99 | handler: function (request, reply) { 100 | reply.view('profile') 101 | } 102 | }, 103 | 104 | logout: { 105 | auth: 'session', 106 | handler: function (request, reply) { 107 | request.cookieAuth.clear() 108 | reply.view('index') 109 | } 110 | } 111 | } 112 | 113 | module.exports = Handler 114 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/implementation/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.dependency([ 'authentication', 'vision' ]) 7 | 8 | server.route(Routes) 9 | server.log('info', 'Plugin registered: redirect to previous page') 10 | 11 | next() 12 | } 13 | 14 | exports.register.attributes = { 15 | name: 'redirect-to-previous-page', 16 | version: '1.0.0' 17 | } 18 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/implementation/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: 'GET', 13 | path: '/login', 14 | config: Handler.showLogin 15 | }, 16 | { 17 | method: 'POST', 18 | path: '/login', 19 | config: Handler.login 20 | }, 21 | { 22 | method: 'GET', 23 | path: '/private', 24 | config: Handler.private 25 | }, 26 | { 27 | method: 'GET', 28 | path: '/profile', 29 | config: Handler.profile 30 | }, 31 | { 32 | method: 'GET', 33 | path: '/logout', 34 | config: Handler.logout 35 | } 36 | ] 37 | 38 | module.exports = Routes 39 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('./authentication') 18 | }, 19 | { 20 | register: require('vision') 21 | }, 22 | { 23 | register: require('./implementation') 24 | } 25 | ], err => { 26 | if (err) { 27 | throw err 28 | } 29 | 30 | server.views({ 31 | engines: { 32 | html: require('handlebars') 33 | }, 34 | path: __dirname + '/views', 35 | layout: 'layout' 36 | }) 37 | 38 | // start your server 39 | server.start(err => { 40 | 41 | if (err) { 42 | throw err 43 | } 44 | 45 | console.log('Server running at: ' + server.info.uri) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/users-db.js: -------------------------------------------------------------------------------- 1 | // hardcoded users object … just for illustration purposes 2 | const users = { 3 | future: { 4 | username: 'future', 5 | password: '$2a$04$YPy8WdAtWswed8b9MfKixebJkVUhEZxQCrExQaxzhcdR2xMmpSJiG', // 'studio' 6 | name: 'Future Studio', 7 | id: '1' 8 | } 9 | } 10 | 11 | module.exports = users -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Hello!

5 | 6 |

7 | Both of the links below require authentication and 8 | you’ll be redirected to the actual page after login. 9 |

10 | 14 | 15 |
16 |
17 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | {{{ content }}} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/views/login.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 |
10 |

Login

11 |

12 | Hi buddy, log in with username future and password studio: 13 |

14 |

15 | Back to the startpage 16 |

17 | 18 | {{#if errormessage}} 19 |
20 |

21 | {{errormessage}} 22 |

23 | {{/if}} 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/views/private.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Private. Shhh!

5 |

6 | You’re the only one who can see this private view :) 7 |

8 | 9 |

10 | Back to the startpage 11 |

12 | 13 |

14 | Logout 15 |

16 |
17 |
18 | -------------------------------------------------------------------------------- /hapi-16/redirect-to-previous-page-after-login/views/profile.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Your Profile

5 | 6 |

7 | Back to the startpage 8 |

9 | 10 |

11 | Logout 12 |

13 |
14 |
15 | -------------------------------------------------------------------------------- /hapi-16/render-handlebars-views/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | var Vision = require('vision') 4 | var Handlebars = require('handlebars') 5 | 6 | 7 | // create new server instance 8 | var server = new Hapi.Server() 9 | 10 | // add server’s connection information 11 | server.connection({ 12 | host: 'localhost', 13 | port: 3000 14 | }) 15 | 16 | // register plugins to server instance 17 | server.register([ 18 | { 19 | register: Vision 20 | }, 21 | { 22 | register: Good, 23 | options: { 24 | ops: { 25 | interval: 10000 26 | }, 27 | reporters: { 28 | console: [ 29 | { 30 | module: 'good-squeeze', 31 | name: 'Squeeze', 32 | args: [ { log: '*', response: '*', request: '*' } ] 33 | }, 34 | { 35 | module: 'good-console' 36 | }, 37 | 'stdout' 38 | ] 39 | } 40 | } 41 | } 42 | ], function (err) { 43 | if (err) { 44 | server.log('error', 'failed to install plugins') 45 | 46 | throw err 47 | } 48 | 49 | server.log('info', 'Plugins registered') 50 | 51 | /** 52 | * view configuration 53 | */ 54 | server.views({ 55 | engines: { 56 | html: Handlebars 57 | }, 58 | path: __dirname + '/views', 59 | layout: true 60 | }) 61 | server.log('info', 'View configuration completed') 62 | 63 | 64 | server.route({ 65 | method: 'GET', 66 | path: '/', 67 | handler: function(request, reply) { 68 | var data = { 69 | title: 'Hapi Render Views', 70 | message: 'Wohoo \\o/ Your view has been rendered successfully!' 71 | } 72 | 73 | reply.view('index', data) 74 | } 75 | }) 76 | server.log('info', 'Route registered') 77 | 78 | // start your server after plugin registration 79 | server.start(function (err) { 80 | if (err) { 81 | server.log('error', 'failed to start server') 82 | server.log('error', err) 83 | 84 | throw err 85 | } 86 | 87 | server.log('info', 'Server running at: ' + server.info.uri) 88 | }) 89 | }) 90 | -------------------------------------------------------------------------------- /hapi-16/render-handlebars-views/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |

{{message}}

3 |
-------------------------------------------------------------------------------- /hapi-16/render-handlebars-views/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | 8 | {{{ content }}} 9 | 10 | 11 | -------------------------------------------------------------------------------- /hapi-16/reply-json/base-route.js: -------------------------------------------------------------------------------- 1 | var baseRoutes = { 2 | register: function (server, options, next) { 3 | var routes = [ 4 | { 5 | method: 'GET', 6 | path: '/', 7 | handler: function (request, reply) { 8 | var data = { 9 | key: 'value', 10 | another: false, 11 | number: 10, 12 | func: function() { 13 | return this.number * 10 14 | } 15 | } 16 | 17 | reply(data) 18 | } 19 | } 20 | ] 21 | 22 | // add defined routes to hapi 23 | server.route(routes) 24 | next() 25 | } 26 | } 27 | 28 | baseRoutes.register.attributes = { 29 | name: 'base-routes', 30 | version: '1.0.0' 31 | } 32 | 33 | module.exports = baseRoutes -------------------------------------------------------------------------------- /hapi-16/reply-json/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/request-headers/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const plugin = { 4 | register: function (server, options, next) { 5 | server.route({ 6 | method: 'GET', 7 | path: '/', 8 | handler: function (request, reply) { 9 | const headers = request.headers 10 | 11 | server.log('info', headers) 12 | 13 | reply(headers) 14 | } 15 | }) 16 | 17 | next() 18 | } 19 | } 20 | 21 | plugin.register.attributes = { 22 | name: 'request-headers', 23 | version: '1.0.0' 24 | } 25 | 26 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/request-headers/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const Good = require('good') 5 | 6 | // create new server instance 7 | let server = new Hapi.Server() 8 | 9 | // add server’s connection information 10 | server.connection({ 11 | host: 'localhost', 12 | port: 3000 13 | }) 14 | 15 | // register plugins to server instance 16 | server.register([ 17 | { 18 | register: require('./base-route') 19 | }, 20 | { 21 | register: Good, 22 | options: { 23 | ops: { 24 | interval: 10000 25 | }, 26 | reporters: { 27 | console: [ 28 | { 29 | module: 'good-squeeze', 30 | name: 'Squeeze', 31 | args: [ { log: '*', response: '*', request: '*' } ] 32 | }, 33 | { 34 | module: 'good-console' 35 | }, 36 | 'stdout' 37 | ] 38 | } 39 | } 40 | } 41 | ], function (err) { 42 | if (err) { 43 | throw err 44 | } 45 | 46 | // start your server after plugin registration 47 | server.start(function (err) { 48 | if (err) { 49 | throw err 50 | } 51 | 52 | server.log('info', 'Server running at: ' + server.info.uri) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /hapi-16/request-payload/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const plugin = { 4 | register: function (server, options, next) { 5 | server.route({ 6 | method: 'POST', 7 | path: '/', 8 | handler: function (request, reply) { 9 | const payload = request.payload; 10 | 11 | server.log('info', payload) 12 | 13 | reply(payload) 14 | } 15 | }) 16 | 17 | next() 18 | } 19 | } 20 | 21 | plugin.register.attributes = { 22 | name: 'wildcard-path-params', 23 | version: '1.0.0' 24 | } 25 | 26 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/request-payload/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/response-status-codes/base-route.js: -------------------------------------------------------------------------------- 1 | var Boom = require('boom') 2 | 3 | var baseRoutes = { 4 | register: function (server, options, next) { 5 | var routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | handler: function (request, reply) { 10 | var data = { 11 | key: 'value' 12 | } 13 | 14 | reply(data).code(201) 15 | } 16 | }, 17 | { 18 | method: 'GET', 19 | path: '/error', 20 | handler: function (request, reply) { 21 | var error = Boom.notFound('Cannot find the requested page') 22 | reply(error) 23 | } 24 | }, 25 | { 26 | method: 'GET', 27 | path: '/empty', 28 | config: { 29 | response: { 30 | emptyStatusCode: 204 31 | }, 32 | handler: function (request, reply) { 33 | reply() 34 | } 35 | } 36 | } 37 | ] 38 | 39 | // add defined routes to hapi 40 | server.route(routes) 41 | next() 42 | } 43 | } 44 | 45 | baseRoutes.register.attributes = { 46 | name: 'response-status', 47 | version: '1.0.0' 48 | } 49 | 50 | module.exports = baseRoutes 51 | -------------------------------------------------------------------------------- /hapi-16/response-status-codes/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/restrict-access-with-scopes/base-routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Boom = require('boom') 4 | const Bcrypt = require('bcrypt') 5 | const Users = require('./users-db') 6 | 7 | const routes = [ 8 | { 9 | method: 'GET', 10 | path: '/', 11 | config: { 12 | auth: { 13 | mode: 'try', 14 | strategy: 'session' 15 | }, 16 | plugins: { 17 | 'hapi-auth-cookie': { 18 | redirectTo: false 19 | } 20 | }, 21 | handler: function (request, reply) { 22 | if (request.auth.isAuthenticated) { 23 | return reply.view('profile') 24 | } 25 | 26 | reply.view('index') 27 | } 28 | } 29 | }, 30 | { 31 | method: 'GET', 32 | path: '/admin', 33 | config: { 34 | auth: { 35 | strategy: 'session', 36 | scope: 'admin' 37 | }, 38 | handler: function (request, reply) { 39 | reply.view('admin') 40 | } 41 | } 42 | }, 43 | { 44 | method: 'POST', 45 | path: '/', 46 | config: { 47 | // auth: 'session', 48 | auth: { 49 | mode: 'try' 50 | }, 51 | plugins: { 52 | 'hapi-auth-cookie': { 53 | redirectTo: false 54 | } 55 | }, 56 | handler: function (request, reply) { 57 | if (request.auth.isAuthenticated) { 58 | return reply.view('Profile') 59 | } 60 | 61 | const username = request.payload.username 62 | let user = Users[ username ] 63 | 64 | if (!user) { 65 | return reply(Boom.notFound('No user registered with given credentials')) 66 | } 67 | 68 | const password = request.payload.password 69 | 70 | return Bcrypt.compare(password, user.password, function (err, isValid) { 71 | if (isValid) { 72 | request.server.log('info', 'user authentication successful') 73 | request.cookieAuth.set(user) 74 | return reply.view('profile') 75 | } 76 | 77 | return reply.view('index') 78 | }) 79 | } 80 | } 81 | }, 82 | { 83 | method: 'GET', 84 | path: '/logout', 85 | config: { 86 | auth: 'session', 87 | handler: function (request, reply) { 88 | request.cookieAuth.clear() 89 | reply.view('index') 90 | } 91 | } 92 | } 93 | ] 94 | 95 | module.exports = routes -------------------------------------------------------------------------------- /hapi-16/restrict-access-with-scopes/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const Good = require('good') 5 | const Vision = require('vision') 6 | const Users = require('./users-db') 7 | const Handlebars = require('handlebars') 8 | const CookieAuth = require('hapi-auth-cookie') 9 | 10 | // create new server instance 11 | const server = new Hapi.Server() 12 | 13 | // add server’s connection information 14 | server.connection({ 15 | host: 'localhost', 16 | port: 3000 17 | }) 18 | 19 | // register plugins to server instance 20 | server.register([ 21 | { 22 | register: Vision 23 | }, 24 | { 25 | register: Good, 26 | options: { 27 | ops: { 28 | interval: 10000 29 | }, 30 | reporters: { 31 | console: [ 32 | { 33 | module: 'good-squeeze', 34 | name: 'Squeeze', 35 | args: [ { log: '*', response: '*', request: '*' } ] 36 | }, 37 | { 38 | module: 'good-console' 39 | }, 40 | 'stdout' 41 | ] 42 | } 43 | } 44 | }, 45 | { 46 | register: CookieAuth 47 | } 48 | ], function (err) { 49 | if (err) { 50 | server.log('error', 'failed to install plugins') 51 | 52 | throw err 53 | } 54 | 55 | server.log('info', 'Plugins registered') 56 | 57 | /** 58 | * view configuration 59 | */ 60 | server.views({ 61 | engines: { 62 | html: Handlebars 63 | }, 64 | path: __dirname + '/views', 65 | layout: true 66 | }) 67 | server.log('info', 'View configuration completed') 68 | 69 | // validation function used for hapi-auth-cookie: optional and checks if the user is still existing 70 | const validation = function (request, session, callback) { 71 | const username = session.username 72 | let user = Users[ username ] 73 | 74 | if (!user) { 75 | return callback(null, false) 76 | } 77 | 78 | server.log('info', 'user authenticated') 79 | callback(err, true, user) 80 | } 81 | 82 | server.auth.strategy('session', 'cookie', true, { 83 | password: 'm!*"2/),p4:xDs%KEgVr7;e#85Ah^WYC', 84 | cookie: 'future-studio-hapi-tutorials-cookie-auth-example', 85 | redirectTo: '/', 86 | isSecure: false, 87 | validateFunc: validation 88 | }) 89 | 90 | server.log('info', 'Registered auth strategy: cookie auth') 91 | 92 | const routes = require('./base-routes') 93 | server.route(routes) 94 | server.log('info', 'Routes registered') 95 | 96 | // start your server after plugin registration 97 | server.start(function (err) { 98 | if (err) { 99 | server.log('error', 'failed to start server') 100 | server.log('error', err) 101 | 102 | throw err 103 | } 104 | 105 | server.log('info', 'Server running at: ' + server.info.uri) 106 | }) 107 | }) 108 | -------------------------------------------------------------------------------- /hapi-16/restrict-access-with-scopes/users-db.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // hardcoded users object … just for illustration purposes 4 | const users = { 5 | future: { 6 | username: 'future', 7 | password: '$2a$04$YPy8WdAtWswed8b9MfKixebJkVUhEZxQCrExQaxzhcdR2xMmpSJiG', // 'studio' 8 | name: 'Future Studio', 9 | scope: [ 'user' ], 10 | id: '1' 11 | }, 12 | admin: { 13 | username: 'admin', 14 | password: '$2a$04$YPy8WdAtWswed8b9MfKixebJkVUhEZxQCrExQaxzhcdR2xMmpSJiG', // 'studio' 15 | name: 'Future Studio Admin', 16 | scope: [ 'admin', 'user' ], 17 | id: '2' 18 | } 19 | } 20 | 21 | module.exports = users -------------------------------------------------------------------------------- /hapi-16/restrict-access-with-scopes/views/admin.html: -------------------------------------------------------------------------------- 1 |
2 |

Admin Panel

3 | 4 |

5 | This view is only reachable and visible for admins! 6 |

7 | 8 |

9 | logout 10 |

11 |
-------------------------------------------------------------------------------- /hapi-16/restrict-access-with-scopes/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |

Hapi Cookie Authentication

3 |

4 | Use the following credentials to log in. 5 |

6 |
    7 |
  • Username: future
  • 8 |
  • Password: studio
  • 9 |
10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
-------------------------------------------------------------------------------- /hapi-16/restrict-access-with-scopes/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hapi — Basic Authentication 5 | 6 | 7 | 8 | {{{ content }}} 9 | 10 | 11 | -------------------------------------------------------------------------------- /hapi-16/restrict-access-with-scopes/views/profile.html: -------------------------------------------------------------------------------- 1 |
2 |

Your Profile

3 |

4 | Admin 5 | logout 6 |

7 |
-------------------------------------------------------------------------------- /hapi-16/routing/base-route.js: -------------------------------------------------------------------------------- 1 | var baseRoutes = { 2 | register: function (server, options, next) { 3 | var routes = [ 4 | // optional parameter 5 | { 6 | method: 'GET', 7 | path: '/{identifier?}', 8 | handler: function (request, reply) { 9 | reply('Hello Future Studio! You requested data for ' + encodeURIComponent(request.params.identifier)) 10 | } 11 | }, 12 | // add exemplary POST route 13 | { 14 | method: [ 'POST', 'PUT' ], 15 | path: '/', 16 | handler: function (request, reply) { 17 | reply('Hey Bro, awesome to see you around!') 18 | } 19 | }, 20 | { 21 | method: 'GET', 22 | path: '/page/{page*}', 23 | handler: function (request, reply) { 24 | var page = request.params.page || 1 25 | reply('Greetings from page: ' + encodeURIComponent(page)) 26 | } 27 | } 28 | ] 29 | 30 | // add defined routes to hapi 31 | server.route(routes) 32 | next() 33 | } 34 | } 35 | 36 | baseRoutes.register.attributes = { 37 | name: 'base-routes', 38 | version: '1.0.0' 39 | } 40 | 41 | module.exports = baseRoutes -------------------------------------------------------------------------------- /hapi-16/routing/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | // start your server after plugin registration 41 | server.start(function (err) { 42 | if (err) { 43 | throw err 44 | } 45 | 46 | server.log('info', 'Server running at: ' + server.info.uri) 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /hapi-16/serve-static-files/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const baseRoutes = { 4 | register: function (server, options, next) { 5 | const routes = [ 6 | { 7 | method: 'GET', 8 | path: '/directory/{file}', 9 | handler: { 10 | directory: { 11 | path: './files' 12 | } 13 | } 14 | }, 15 | { 16 | method: 'GET', 17 | path: '/sub-directory/{file*}', 18 | handler: { 19 | directory: { 20 | path: './files' 21 | } 22 | } 23 | }, 24 | { 25 | method: 'GET', 26 | path: '/file/{file*}', 27 | handler: function (request, reply) { 28 | const file = request.params.file 29 | 30 | console.log(file) 31 | 32 | reply.file('files/' + file) 33 | } 34 | } 35 | ] 36 | 37 | // add defined routes to hapi 38 | server.route(routes) 39 | next() 40 | } 41 | } 42 | 43 | baseRoutes.register.attributes = { 44 | name: 'serve-static-files', 45 | version: '1.0.0' 46 | } 47 | 48 | module.exports = baseRoutes 49 | -------------------------------------------------------------------------------- /hapi-16/serve-static-files/files/js/test.js: -------------------------------------------------------------------------------- 1 | console.log('This log is from the test.js file') -------------------------------------------------------------------------------- /hapi-16/serve-static-files/files/main.js: -------------------------------------------------------------------------------- 1 | 'Hello' -------------------------------------------------------------------------------- /hapi-16/serve-static-files/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const Good = require('good') 5 | const Inert = require('inert') 6 | 7 | // create new server instance 8 | const server = new Hapi.Server() 9 | 10 | // add server’s connection information 11 | server.connection({ 12 | host: 'localhost', 13 | port: 3000 14 | }) 15 | 16 | // register plugins to server instance 17 | server.register([ 18 | { 19 | register: Inert 20 | }, 21 | { 22 | register: require('./base-route') 23 | }, 24 | { 25 | register: Good, 26 | options: { 27 | ops: { 28 | interval: 10000 29 | }, 30 | reporters: { 31 | console: [ 32 | { 33 | module: 'good-squeeze', 34 | name: 'Squeeze', 35 | args: [ { log: '*', response: '*', request: '*' } ] 36 | }, 37 | { 38 | module: 'good-console' 39 | }, 40 | 'stdout' 41 | ] 42 | } 43 | } 44 | } 45 | ], function (err) { 46 | // start your server after plugin registration 47 | server.start(function (err) { 48 | if (err) { 49 | throw err 50 | } 51 | 52 | server.log('info', 'Server running at: ' + server.info.uri) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/base/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = { 4 | index: { 5 | handler: function (request, reply) { 6 | reply.view('index').test() 7 | } 8 | }, 9 | 10 | missing: { 11 | handler: function (request, reply) { 12 | reply.view('404').code(404) 13 | } 14 | } 15 | } 16 | 17 | module.exports = Handler 18 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/base/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.dependency([ 'vision' ]) 7 | 8 | server.route(Routes) 9 | server.log('info', 'Plugin registered: 404 handler') 10 | 11 | next() 12 | } 13 | 14 | exports.register.attributes = { 15 | name: '404-handler', 16 | version: '1.0.0' 17 | } 18 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/base/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | { 12 | method: 'GET', 13 | path: '/{path*}', 14 | config: Handler.missing 15 | } 16 | ] 17 | 18 | module.exports = Routes 19 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('vision') 18 | }, 19 | { 20 | register: require('./base') 21 | }, 22 | { 23 | register: require('hapi-dev-errors'), 24 | options: { 25 | //template: 'error', 26 | showErrors: process.env.NODE_ENV !== 'production' 27 | } 28 | } 29 | ], err => { 30 | if (err) { 31 | throw err 32 | } 33 | 34 | server.views({ 35 | engines: { 36 | html: require('handlebars') 37 | }, 38 | path: __dirname + '/views', 39 | layout: 'layout' 40 | }) 41 | 42 | // start your server 43 | server.start(err => { 44 | 45 | if (err) { 46 | throw err 47 | } 48 | 49 | console.log('Server running at: ' + server.info.uri) 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/show-error-stacktrace/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %title% (%statusCode%) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 |

%title% (%statusCode%)

18 |

%message%

19 | 20 |
21 |                 %stacktrace%
22 |             
23 | 24 |

25 | Called URL 26 |
27 | 28 | %method% %url% 29 | 30 |

31 | 32 |
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/show-error-stacktrace/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Fs = require('fs') 4 | const Path = require('path') 5 | const TemplatePath = Path.join(__dirname, './error.html') 6 | 7 | exports.register = (server, options, next) => { 8 | 9 | // default option values 10 | const defaults = { 11 | showErrors: false 12 | } 13 | 14 | const config = Object.assign(defaults, options) 15 | 16 | // want to render specific template? Better make sure `vision` is available :) 17 | if (config.template) { 18 | server.dependency([ 'vision' ]) 19 | } 20 | 21 | // read and keep the default error template 22 | const errorTemplate = Fs.readFileSync(TemplatePath, 'utf8') 23 | 24 | // extend the request lifecycle at `onPreResponse` 25 | // to change the default error handling behavior (if enabled) 26 | server.ext('onPreResponse', (request, reply) => { 27 | if (!config.showErrors) { 28 | return reply.continue() 29 | } 30 | 31 | // response shortcut 32 | const response = request.response 33 | 34 | // only show "bad implementation" developer errors, status code 500 35 | if (response.isDeveloperError) { 36 | const accept = request.raw.req.headers.accept 37 | const statusCode = response.output.payload.statusCode 38 | 39 | const errorResponse = { 40 | title: response.output.payload.error, 41 | statusCode: statusCode, 42 | message: response.message, 43 | method: request.raw.req.method, 44 | url: request.url.path, 45 | payload: request.raw.req.method !== 'GET' ? request.payload : '', 46 | stacktrace: response.stack 47 | } 48 | 49 | // take priority: check header if there's a JSON REST request 50 | if (accept && accept.match(/json/)) { 51 | return reply(errorResponse).code(statusCode) 52 | } 53 | 54 | // did the user explicitly specify an error template 55 | if (options.template) { 56 | return reply.view(options.template, errorResponse).code(statusCode) 57 | } 58 | 59 | // prepare the error template and replace %placeholder% with error specific details 60 | const output = errorTemplate.replace(/%(\w+)%/g, (full, token) => { 61 | return errorResponse[ token ] || '' 62 | }) 63 | 64 | return reply(output).code(statusCode) 65 | } 66 | 67 | // go ahead with the response, no developer error detected 68 | return reply.continue() 69 | }) 70 | 71 | // server.log('info', 'Plugin registered: show error stacktrace') 72 | 73 | next() 74 | } 75 | 76 | exports.register.attributes = { 77 | name: 'show-error-stacktrace', 78 | version: '1.0.0' 79 | } 80 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/views/404.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

404!

5 |

6 | Sorry buddy, this resouce isn’t available. 7 |

8 | 9 |

10 | Back home 11 |

12 |
13 |
14 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/views/error.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{title}} ({{statusCode}})

5 |

6 | Called URL 7 |
8 | 9 | {{method}} {{url}} 10 | 11 |

12 | 13 |

14 | Error Details 15 |
16 | {{message}} 17 |

18 | 19 | {{#if stacktrace}} 20 |
21 |                 
22 |                     {{~ stacktrace ~}}
23 |                 
24 |             
25 | {{/if}} 26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Hello!

5 | 6 |

7 | Go anywhere, you’ll see the 404 :) 8 |

9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /hapi-16/show-error-stacktrace-in-browser/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Better hapi errors in dev 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | {{{ content }}} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/.eslintignore: -------------------------------------------------------------------------------- 1 | package.json -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'standard' 3 | } 4 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/base/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = { 4 | index: { 5 | handler: (request, reply) => { 6 | reply({ name: 'Marcus', isDeveloper: true }) 7 | } 8 | }, 9 | 10 | injectData: { 11 | handler: (request, reply) => { 12 | const data = Object.assign({}, request.params, request.query, request.payload, request.headers) 13 | 14 | // if you’re with Node.js v8.6 or later, the spread operator is for you :) 15 | // const data = { ...request.params, ...request.query, ...request.payload, ...request.headers } 16 | 17 | reply(data) 18 | } 19 | } 20 | } 21 | 22 | module.exports = Handler 23 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/base/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.route(Routes) 7 | server.log('info', 'Plugin registered: test hapi handles by injecting requests') 8 | 9 | next() 10 | } 11 | 12 | exports.register.attributes = { 13 | name: 'hapi-testing-1', 14 | version: '1.0.0' 15 | } 16 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/base/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | }, 11 | 12 | { 13 | method: 'POST', 14 | path: '/inject-data/{page}', 15 | config: Handler.injectData 16 | } 17 | ] 18 | 19 | module.exports = Routes 20 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-tutorials-hapi-testing", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "test": "./../../node_modules/lab/bin/lab --assert code --leaks --coverage", 6 | "test-lint": "./../../node_modules/lab/bin/lab --assert code --leaks --coverage --lint", 7 | "test-lint-format": 8 | "./../../node_modules/eslint/bin/eslint.js --fix ./* && ./../../node_modules/lab/bin/lab --assert code --leaks --coverage --lint" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('vision') 18 | }, 19 | { 20 | register: require('./base') 21 | } 22 | ]).then(() => { 23 | // start your server 24 | server.start(function (err) { 25 | if (err) { 26 | throw err 27 | } 28 | 29 | console.log('Server running at: ' + server.info.uri) 30 | }) 31 | }).catch(err => { 32 | throw err 33 | }) 34 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/test/before-and-after-test-actions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Lab = require('lab') 4 | const Hapi = require('hapi') 5 | const Path = require('path') 6 | 7 | let server 8 | 9 | const lab = (exports.lab = Lab.script()) 10 | const experiment = lab.experiment 11 | const test = lab.test 12 | 13 | experiment('hapi-tutorials run actions before and after tests', () => { 14 | // use lab.before if you need to execute code before the tests are executed 15 | // this is beneficial for asynchronous operations and initializations 16 | lab.before(done => { 17 | // run before test 18 | done() 19 | }) 20 | 21 | // with lab.beforeEach you can run code that is executed before every single test 22 | // like with lab.before, this is helpful for async operations 23 | lab.beforeEach(done => { 24 | // run before every single test 25 | server = new Hapi.Server() 26 | server.connection({ port: 3000 }) 27 | server 28 | .register({ 29 | register: require(Path.resolve(__dirname, '..', 'base')) 30 | }) 31 | .then(() => { 32 | done() 33 | }) 34 | .catch(err => { 35 | done(err) 36 | }) 37 | }) 38 | 39 | // please have a look at the comments on lab.before and lab.beforeEach ;-) 40 | lab.after(done => { 41 | done() 42 | }) 43 | 44 | // please have a look at the comments on lab.before and lab.beforeEach ;-) 45 | lab.afterEach(done => { 46 | // run after every single test 47 | done() 48 | }) 49 | 50 | test('resolves already', done => { 51 | done() 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/test/inject-payload-headers-params.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Lab = require('lab') 4 | const Code = require('code') 5 | const Hapi = require('hapi') 6 | const Path = require('path') 7 | const Qs = require('querystring') 8 | 9 | const server = new Hapi.Server() 10 | server.connection({ port: 3000 }) 11 | server 12 | .register({ 13 | register: require(Path.resolve(__dirname, '..', 'base')) 14 | }) 15 | .catch(err => { 16 | throw err 17 | }) 18 | 19 | const lab = (exports.lab = Lab.script()) 20 | const experiment = lab.experiment 21 | const test = lab.test 22 | 23 | experiment('hapi-tutorials base plugin', () => { 24 | test('test if the plugin returns JSON by default', done => { 25 | const query = Qs.stringify({ name: 'Marcus' }) 26 | const page = 1 27 | 28 | const options = { 29 | url: `/inject-data/${page}?${query}`, 30 | method: 'POST', 31 | payload: { 32 | isGeek: false 33 | }, 34 | headers: { 35 | 'X-Testing-Header': 'Testing-123' 36 | } 37 | } 38 | 39 | server.inject(options, response => { 40 | const payload = JSON.parse(response.payload || '{}') 41 | 42 | Code.expect(response.statusCode).to.equal(200) 43 | Code.expect(payload.name).to.equal('Marcus') 44 | Code.expect(payload.isGeek).to.equal(false) 45 | Code.expect(parseInt(payload.page)).to.equal(page) 46 | Code.expect(payload['x-testing-header']).to.equal('Testing-123') 47 | 48 | done() 49 | }) 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /hapi-16/testing-inject-requests/test/plugin-index-responds-with-json.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Lab = require('lab') 4 | const Code = require('code') 5 | const Hapi = require('hapi') 6 | 7 | const server = new Hapi.Server() 8 | server.connection() 9 | 10 | server.route({ 11 | method: 'GET', 12 | path: '/', 13 | handler: (request, reply) => { 14 | reply({ name: 'Marcus', isDeveloper: true }) 15 | } 16 | }) 17 | 18 | const lab = (exports.lab = Lab.script()) 19 | const experiment = lab.experiment 20 | const test = lab.test 21 | 22 | experiment('getting started with hapi testing', () => { 23 | test('test if the route returns JSON by default', done => { 24 | const options = { 25 | method: 'GET', 26 | url: '/' 27 | } 28 | 29 | server.inject(options, response => { 30 | const payload = JSON.parse(response.payload || '{}') 31 | 32 | Code.expect(response.statusCode).to.equal(200) 33 | Code.expect(payload.name).to.equal('Marcus') 34 | Code.expect(payload.isDeveloper).to.equal(true) 35 | 36 | done() 37 | }) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /hapi-16/upload-files/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const plugin = { 4 | register: function (server, options, next) { 5 | const routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: { 10 | handler: function (request, reply) { 11 | reply('Send a file in POST with name "file" to /upload') 12 | } 13 | } 14 | }, 15 | { 16 | method: 'POST', 17 | path: '/upload', 18 | config: { 19 | handler: function (request, reply) { 20 | const payload = request.payload 21 | 22 | console.log(payload) 23 | 24 | reply(request.headers) 25 | }, 26 | payload: { 27 | maxBytes: 209715200, 28 | output: 'file' 29 | } 30 | } 31 | }, 32 | { 33 | method: 'POST', 34 | path: '/upload-stream', 35 | config: { 36 | handler: function (request, reply) { 37 | const payload = request.payload 38 | 39 | console.log(payload) 40 | 41 | reply(request.headers) 42 | }, 43 | payload: { 44 | output: 'stream' 45 | } 46 | } 47 | }, 48 | { 49 | method: 'POST', 50 | path: '/upload-data', 51 | config: { 52 | handler: function (request, reply) { 53 | const payload = request.payload 54 | 55 | console.log(payload) 56 | 57 | reply(request.headers) 58 | }, 59 | payload: { 60 | output: 'data' 61 | } 62 | } 63 | } 64 | ] 65 | 66 | // add defined routes to hapi 67 | server.route(routes) 68 | 69 | next() 70 | } 71 | } 72 | 73 | plugin.register.attributes = { 74 | name: 'upload-files', 75 | version: '1.0.0' 76 | } 77 | 78 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/upload-files/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const Good = require('good') 5 | 6 | // create new server instance 7 | const server = new Hapi.Server() 8 | 9 | // add server’s connection information 10 | server.connection({ 11 | host: 'localhost', 12 | port: 3000 13 | }) 14 | 15 | // register plugins to server instance 16 | server.register([ 17 | { 18 | register: require('./base-route') 19 | }, 20 | { 21 | register: Good, 22 | options: { 23 | ops: { 24 | interval: 10000 25 | }, 26 | reporters: { 27 | console: [ 28 | { 29 | module: 'good-squeeze', 30 | name: 'Squeeze', 31 | args: [ { log: '*', response: '*', request: '*' } ] 32 | }, 33 | { 34 | module: 'good-console' 35 | }, 36 | 'stdout' 37 | ] 38 | } 39 | } 40 | } 41 | ], function (err) { 42 | if (err) { 43 | throw err 44 | } 45 | 46 | // start your server after plugin registration 47 | server.start(function (err) { 48 | if (err) { 49 | throw err 50 | } 51 | 52 | server.log('info', 'Server running at: ' + server.info.uri) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /hapi-16/validation-parameters-and-payload/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Joi = require('joi') 4 | 5 | const plugin = { 6 | register: function (server, options, next) { 7 | server.route({ 8 | method: 'POST', 9 | path: '/{page}', 10 | config: { 11 | handler: function (request, reply) { 12 | reply('You’ve passed all the validations :)') 13 | }, 14 | validate: { 15 | params: { 16 | page: Joi.number().required() 17 | }, 18 | query: { 19 | test: Joi.number().optional() 20 | }, 21 | payload: { 22 | username: Joi.string().required() 23 | }, 24 | headers: { 25 | 'user-agent': Joi.string() 26 | }, 27 | options: { 28 | allowUnknown: true 29 | } 30 | } 31 | } 32 | }) 33 | 34 | next() 35 | } 36 | } 37 | 38 | plugin.register.attributes = { 39 | name: 'validate-all-parameters-payload-headers', 40 | version: '1.0.0' 41 | } 42 | 43 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/validation-parameters-and-payload/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: Good, 17 | options: { 18 | ops: { 19 | interval: 10000 20 | }, 21 | reporters: { 22 | console: [ 23 | { 24 | module: 'good-squeeze', 25 | name: 'Squeeze', 26 | args: [ { log: '*', response: '*', request: '*' } ] 27 | }, 28 | { 29 | module: 'good-console' 30 | }, 31 | 'stdout' 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | register: require('./base-route') 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/validation-path-parameter/base-route.js: -------------------------------------------------------------------------------- 1 | var Joi = require('joi') 2 | 3 | var plugin = { 4 | register: function (server, options, next) { 5 | var routes = [ 6 | { 7 | method: 'GET', 8 | path: '/tutorials/page/{page}', 9 | config: { 10 | handler: function (request, reply) { 11 | var pathParams = request.params 12 | 13 | server.log('info', pathParams) 14 | 15 | reply(pathParams) 16 | }, 17 | validate: { 18 | params: { 19 | page: Joi.number().min(1) 20 | } 21 | } 22 | } 23 | } 24 | ] 25 | 26 | // add defined routes to hapi 27 | server.route(routes) 28 | 29 | next() 30 | } 31 | } 32 | 33 | plugin.register.attributes = { 34 | name: 'validate-path-parameters', 35 | version: '1.0.0' 36 | } 37 | 38 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/validation-path-parameter/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: Good, 17 | options: { 18 | ops: { 19 | interval: 10000 20 | }, 21 | reporters: { 22 | console: [ 23 | { 24 | module: 'good-squeeze', 25 | name: 'Squeeze', 26 | args: [ { log: '*', response: '*', request: '*' } ] 27 | }, 28 | { 29 | module: 'good-console' 30 | }, 31 | 'stdout' 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | register: require('./base-route') 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/validation-payload/base-route.js: -------------------------------------------------------------------------------- 1 | var Joi = require('joi') 2 | 3 | var plugin = { 4 | register: function (server, options, next) { 5 | var routes = [ 6 | { 7 | method: 'POST', 8 | path: '/', 9 | config: { 10 | handler: function (request, reply) { 11 | var payload = request.payload 12 | 13 | server.log('info', payload) 14 | 15 | reply(payload) 16 | }, 17 | validate: { 18 | payload: { 19 | email: Joi.string().email().required(), 20 | password: Joi.string().min(6).max(200).required() 21 | } 22 | } 23 | } 24 | } 25 | ] 26 | 27 | // add defined routes to hapi 28 | server.route(routes) 29 | 30 | next() 31 | } 32 | } 33 | 34 | plugin.register.attributes = { 35 | name: 'validation-request-payload', 36 | version: '1.0.0' 37 | } 38 | 39 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/validation-payload/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/validation-query-parameter/base-route.js: -------------------------------------------------------------------------------- 1 | var Joi = require('joi') 2 | 3 | var plugin = { 4 | register: function (server, options, next) { 5 | var routes = [ 6 | { 7 | method: 'GET', 8 | path: '/tutorials', 9 | config: { 10 | handler: function (request, reply) { 11 | var queryParams = request.query 12 | 13 | server.log('info', queryParams) 14 | 15 | reply(queryParams) 16 | }, 17 | validate: { 18 | query: { 19 | filter: Joi.array().items(Joi.string().valid('premium', 'video')).single(), 20 | page: Joi.number().min(1) 21 | } 22 | } 23 | } 24 | } 25 | ] 26 | 27 | // add defined routes to hapi 28 | server.route(routes) 29 | 30 | next() 31 | } 32 | } 33 | 34 | plugin.register.attributes = { 35 | name: 'validate-query-parameters', 36 | version: '1.0.0' 37 | } 38 | 39 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/validation-query-parameter/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: Good, 17 | options: { 18 | ops: { 19 | interval: 10000 20 | }, 21 | reporters: { 22 | console: [ 23 | { 24 | module: 'good-squeeze', 25 | name: 'Squeeze', 26 | args: [ { log: '*', response: '*', request: '*' } ] 27 | }, 28 | { 29 | module: 'good-console' 30 | }, 31 | 'stdout' 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | register: require('./base-route') 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/validation-request-headers/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Joi = require('joi') 4 | 5 | const plugin = { 6 | register: function (server, options, next) { 7 | server.route({ 8 | method: 'GET', 9 | path: '/', 10 | config: { 11 | handler: function (request, reply) { 12 | const headers = request.headers 13 | 14 | server.log('info', headers) 15 | 16 | reply(headers) 17 | }, 18 | validate: { 19 | headers: { 20 | 'user-agent': Joi.string().required(), 21 | username: Joi.string().required() 22 | }, 23 | options: { 24 | allowUnknown: true 25 | } 26 | } 27 | } 28 | }) 29 | 30 | next() 31 | } 32 | } 33 | 34 | plugin.register.attributes = { 35 | name: 'validation-return-all-errors', 36 | version: '1.0.0' 37 | } 38 | 39 | module.exports = plugin 40 | -------------------------------------------------------------------------------- /hapi-16/validation-request-headers/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const Good = require('good') 5 | 6 | // create new server instance 7 | const server = new Hapi.Server() 8 | 9 | // add server’s connection information 10 | server.connection({ 11 | host: 'localhost', 12 | port: 3000 13 | }) 14 | 15 | // register plugins to server instance 16 | server.register([ 17 | { 18 | register: require('./base-route') 19 | }, 20 | { 21 | register: Good, 22 | options: { 23 | ops: { 24 | interval: 10000 25 | }, 26 | reporters: { 27 | console: [ 28 | { 29 | module: 'good-squeeze', 30 | name: 'Squeeze', 31 | args: [ { log: '*', response: '*', request: '*' } ] 32 | }, 33 | { 34 | module: 'good-console' 35 | }, 36 | 'stdout' 37 | ] 38 | } 39 | } 40 | } 41 | ], function (err) { 42 | if (err) { 43 | throw err 44 | } 45 | 46 | // start your server after plugin registration 47 | server.start(function (err) { 48 | if (err) { 49 | throw err 50 | } 51 | 52 | server.log('info', 'Server running at: ' + server.info.uri) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /hapi-16/validation-return-all-errors/base-route.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Joi = require('joi') 4 | 5 | const plugin = { 6 | register: function (server, options, next) { 7 | server.route({ 8 | method: 'POST', 9 | path: '/', 10 | config: { 11 | handler: function (request, reply) { 12 | reply('You’ve passed all the validations :)') 13 | }, 14 | validate: { 15 | payload: { 16 | username: Joi.string().required(), 17 | password: Joi.string().min(6).required(), 18 | email: Joi.string().email().required() 19 | }, 20 | options: { 21 | abortEarly: false 22 | } 23 | } 24 | } 25 | }) 26 | 27 | next() 28 | } 29 | } 30 | 31 | plugin.register.attributes = { 32 | name: 'validation-request-headers', 33 | version: '1.0.0' 34 | } 35 | 36 | module.exports = plugin 37 | -------------------------------------------------------------------------------- /hapi-16/validation-return-all-errors/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | const Good = require('good') 5 | 6 | // create new server instance 7 | const server = new Hapi.Server() 8 | 9 | // add server’s connection information 10 | server.connection({ 11 | host: 'localhost', 12 | port: 3000 13 | }) 14 | 15 | // register plugins to server instance 16 | server.register([ 17 | { 18 | register: require('./base-route') 19 | }, 20 | { 21 | register: Good, 22 | options: { 23 | ops: { 24 | interval: 10000 25 | }, 26 | reporters: { 27 | console: [ 28 | { 29 | module: 'good-squeeze', 30 | name: 'Squeeze', 31 | args: [ { log: '*', response: '*', request: '*' } ] 32 | }, 33 | { 34 | module: 'good-console' 35 | }, 36 | 'stdout' 37 | ] 38 | } 39 | } 40 | } 41 | ], function (err) { 42 | if (err) { 43 | throw err 44 | } 45 | 46 | // start your server after plugin registration 47 | server.start(function (err) { 48 | if (err) { 49 | throw err 50 | } 51 | 52 | server.log('info', 'Server running at: ' + server.info.uri) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /hapi-16/vuejs-and-handlebars/index/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = { 4 | index: { 5 | handler: function (request, reply) { 6 | reply.view('index') 7 | } 8 | } 9 | } 10 | 11 | module.exports = Handler 12 | -------------------------------------------------------------------------------- /hapi-16/vuejs-and-handlebars/index/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Routes = require('./routes') 4 | 5 | exports.register = (server, options, next) => { 6 | server.dependency([ 'vision' ]) 7 | 8 | server.route(Routes) 9 | server.log('info', 'Plugin registered: use Vue.js with Handlebars in hapi') 10 | 11 | next() 12 | } 13 | 14 | exports.register.attributes = { 15 | name: 'vue-and-handlebars', 16 | version: '1.0.0' 17 | } 18 | -------------------------------------------------------------------------------- /hapi-16/vuejs-and-handlebars/index/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Handler = require('./handler') 4 | 5 | const Routes = [ 6 | { 7 | method: 'GET', 8 | path: '/', 9 | config: Handler.index 10 | } 11 | ] 12 | 13 | module.exports = Routes 14 | -------------------------------------------------------------------------------- /hapi-16/vuejs-and-handlebars/server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('hapi') 4 | 5 | // create new server instance 6 | const server = new Hapi.Server() 7 | 8 | // add server’s connection information 9 | server.connection({ 10 | host: 'localhost', 11 | port: 3000 12 | }) 13 | 14 | // register plugins to server instance 15 | server.register([ 16 | { 17 | register: require('vision') 18 | }, 19 | { 20 | register: require('./index') 21 | } 22 | ], function (err) { 23 | if (err) { 24 | throw err 25 | } 26 | 27 | server.views({ 28 | engines: { 29 | html: require('handlebars') 30 | }, 31 | path: __dirname + '/views', 32 | layout: 'layout' 33 | }) 34 | 35 | // start your server 36 | server.start(function (err) { 37 | 38 | if (err) { 39 | throw err 40 | } 41 | 42 | console.log('Server running at: ' + server.info.uri) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /hapi-16/vuejs-and-handlebars/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Use Vue.js and Handlebars in hapi

5 |

6 | Both, Vue.js and Handlebars use Mustache \{{ tag }} templates 7 | to render properties into views. This tutorial shows you how to bring 8 | both worlds together: 9 | server side Handlebars and client side Vue.js rendering. 10 |

11 |
12 |
13 | 14 | 15 |
16 |
17 |

18 | Name is: \{{ name }} 19 |

20 |
21 |
22 | 23 | 24 | 33 | -------------------------------------------------------------------------------- /hapi-16/vuejs-and-handlebars/views/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Vue.js and Handlebars in hapi 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | {{{ content }}} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /hapi-16/wildcard-path-params/base-route.js: -------------------------------------------------------------------------------- 1 | var plugin = { 2 | register: function (server, options, next) { 3 | var routes = [ 4 | { 5 | method: 'GET', 6 | path: '/js/{file*}', 7 | handler: function (request, reply) { 8 | // this route matches everything except the restrictive route definition below 9 | var params = request.params 10 | 11 | server.log('info', params) 12 | 13 | reply(params) 14 | } 15 | }, 16 | { 17 | method: 'GET', 18 | path: '/filter/{type*2}', 19 | handler: function (request, reply) { 20 | // this route matches only if 2 path segments are provided after "filter" 21 | var params = request.params 22 | 23 | server.log('info', params) 24 | 25 | reply(params) 26 | } 27 | } 28 | ] 29 | 30 | // add defined routes to hapi 31 | server.route(routes) 32 | 33 | next() 34 | } 35 | } 36 | 37 | plugin.register.attributes = { 38 | name: 'wildcard-path-params', 39 | version: '1.0.0' 40 | } 41 | 42 | module.exports = plugin -------------------------------------------------------------------------------- /hapi-16/wildcard-path-params/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | var Good = require('good') 3 | 4 | // create new server instance 5 | var server = new Hapi.Server() 6 | 7 | // add server’s connection information 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }) 12 | 13 | // register plugins to server instance 14 | server.register([ 15 | { 16 | register: require('./base-route') 17 | }, 18 | { 19 | register: Good, 20 | options: { 21 | ops: { 22 | interval: 10000 23 | }, 24 | reporters: { 25 | console: [ 26 | { 27 | module: 'good-squeeze', 28 | name: 'Squeeze', 29 | args: [ { log: '*', response: '*', request: '*' } ] 30 | }, 31 | { 32 | module: 'good-console' 33 | }, 34 | 'stdout' 35 | ] 36 | } 37 | } 38 | } 39 | ], function (err) { 40 | if (err) { 41 | throw err 42 | } 43 | 44 | // start your server after plugin registration 45 | server.start(function (err) { 46 | if (err) { 47 | throw err 48 | } 49 | 50 | server.log('info', 'Server running at: ' + server.info.uri) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /hapi-16/write-your-own-plugin/base-route.js: -------------------------------------------------------------------------------- 1 | var baseRoutes = { 2 | register: function (server, options, next) { 3 | // add “hello world” route 4 | server.route({ 5 | method: 'GET', 6 | path: '/', 7 | handler: function (request, reply) { 8 | reply('Hello Future Studio!') 9 | } 10 | }) 11 | 12 | next() 13 | } 14 | } 15 | 16 | baseRoutes.register.attributes = { 17 | name: 'base-routes', 18 | version: '1.0.0' 19 | } 20 | 21 | module.exports = baseRoutes -------------------------------------------------------------------------------- /hapi-16/write-your-own-plugin/server.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi') 2 | 3 | // create new server instance 4 | var server = new Hapi.Server() 5 | 6 | // add server’s connection information 7 | server.connection({ 8 | host: 'localhost', 9 | port: 3000 10 | }) 11 | 12 | // register plugins to server instance 13 | server.register({ 14 | register: require('./base-route') 15 | }) 16 | 17 | // start your server 18 | server.start(function (err) { 19 | if (err) { 20 | throw err 21 | } 22 | 23 | console.log('Server running at: ' + server.info.uri) 24 | }) 25 | -------------------------------------------------------------------------------- /hapi-18/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": [ 7 | "standard" 8 | ], 9 | "plugins": [ 10 | "standard" 11 | ], 12 | "parserOptions": { 13 | "ecmaVersion": 2018 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /hapi-18/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hapi-18", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@hapi/hapi": "~18.3.1" 14 | }, 15 | "devDependencies": { 16 | "eslint": "~6.0.1", 17 | "eslint-config-standard": "~13.0.1", 18 | "eslint-plugin-import": "~2.18.0", 19 | "eslint-plugin-node": "~9.1.0", 20 | "eslint-plugin-promise": "~4.2.1", 21 | "eslint-plugin-standard": "~4.0.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /hapi-18/redirect-including-request-payload/redirect-including-request-payload.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Hapi = require('@hapi/hapi') 4 | 5 | const server = new Hapi.Server({ 6 | host: 'localhost', 7 | port: 3000 8 | }) 9 | 10 | async function start() { 11 | server.route([ 12 | { 13 | method: 'POST', 14 | path: '/', 15 | handler: (_, h) => { 16 | return h.redirect('/new').code(307) 17 | } 18 | }, 19 | { 20 | method: 'POST', 21 | path: '/new', 22 | handler: ({ payload }) => { 23 | return { 24 | message: 'Received your request including the payload!', 25 | payload 26 | } 27 | } 28 | } 29 | ]) 30 | 31 | await server.start() 32 | console.log('Server running on %s', server.info.uri); 33 | } 34 | 35 | start() 36 | --------------------------------------------------------------------------------