├── .gitignore ├── README.md ├── package.json ├── routes └── books.js └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | #Ignore Mac DS_Store files 2 | .DS_Store 3 | **/.DS_Store 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directory 31 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 32 | node_modules 33 | 34 | # Optional npm cache directory 35 | .npm 36 | 37 | # Optional REPL history 38 | .node_repl_history 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #RESTful API using hapi.js and MongoDB 2 | 3 | This is the code for this blog-post: [Build a RESTful API using hapi.js and MongoDB](http://mph-web.de/build-a-restful-api-using-hapi-js-and-mongodb/) 4 | 5 | ##How to setup? 6 | 7 | You should have a current version of node installed and a local MongoDB server running. Now just clone the repository and execute these two commands: 8 | 9 | ``` 10 | npm install 11 | node server.js 12 | ``` 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hapi-rest-mongo", 3 | "version": "1.0.0", 4 | "description": "Simple REST project with hapijs and mongodb.", 5 | "main": "server.js", 6 | "private": true, 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Patrick Meier", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "boom": "^4.2.0", 14 | "hapi": "^16.1.0", 15 | "joi": "^10.2.2", 16 | "mongojs": "^2.4.0", 17 | "node-uuid": "^1.4.7" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /routes/books.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Boom = require('boom'); 4 | const uuid = require('node-uuid'); 5 | const Joi = require('joi'); 6 | 7 | exports.register = function (server, options, next) { 8 | 9 | const db = server.app.db; 10 | 11 | server.route({ 12 | method: 'GET', 13 | path: '/books', 14 | handler: function (request, reply) { 15 | 16 | db.books.find((err, docs) => { 17 | 18 | if (err) { 19 | return reply(Boom.wrap(err, 'Internal MongoDB error')); 20 | } 21 | 22 | reply(docs); 23 | }); 24 | 25 | } 26 | }); 27 | 28 | server.route({ 29 | method: 'GET', 30 | path: '/books/{id}', 31 | handler: function (request, reply) { 32 | 33 | db.books.findOne({ 34 | _id: request.params.id 35 | }, (err, doc) => { 36 | 37 | if (err) { 38 | return reply(Boom.wrap(err, 'Internal MongoDB error')); 39 | } 40 | 41 | if (!doc) { 42 | return reply(Boom.notFound()); 43 | } 44 | 45 | reply(doc); 46 | }); 47 | 48 | } 49 | }); 50 | 51 | server.route({ 52 | method: 'POST', 53 | path: '/books', 54 | handler: function (request, reply) { 55 | 56 | const book = request.payload; 57 | 58 | //Create an id 59 | book._id = uuid.v1(); 60 | 61 | db.books.save(book, (err, result) => { 62 | 63 | if (err) { 64 | return reply(Boom.wrap(err, 'Internal MongoDB error')); 65 | } 66 | 67 | reply(book); 68 | }); 69 | }, 70 | config: { 71 | validate: { 72 | payload: { 73 | title: Joi.string().min(10).max(50).required(), 74 | author: Joi.string().min(10).max(50).required(), 75 | isbn: Joi.number() 76 | } 77 | } 78 | } 79 | }); 80 | 81 | server.route({ 82 | method: 'PATCH', 83 | path: '/books/{id}', 84 | handler: function (request, reply) { 85 | 86 | db.books.update({ 87 | _id: request.params.id 88 | }, { 89 | $set: request.payload 90 | }, function (err, result) { 91 | 92 | if (err) { 93 | return reply(Boom.wrap(err, 'Internal MongoDB error')); 94 | } 95 | 96 | if (result.n === 0) { 97 | return reply(Boom.notFound()); 98 | } 99 | 100 | reply().code(204); 101 | }); 102 | }, 103 | config: { 104 | validate: { 105 | payload: Joi.object({ 106 | title: Joi.string().min(10).max(50).optional(), 107 | author: Joi.string().min(10).max(50).optional(), 108 | isbn: Joi.number().optional() 109 | }).required().min(1) 110 | } 111 | } 112 | }); 113 | 114 | server.route({ 115 | method: 'DELETE', 116 | path: '/books/{id}', 117 | handler: function (request, reply) { 118 | 119 | db.books.remove({ 120 | _id: request.params.id 121 | }, function (err, result) { 122 | 123 | if (err) { 124 | return reply(Boom.wrap(err, 'Internal MongoDB error')); 125 | } 126 | 127 | if (result.n === 0) { 128 | return reply(Boom.notFound()); 129 | } 130 | 131 | reply().code(204); 132 | }); 133 | } 134 | }); 135 | 136 | return next(); 137 | }; 138 | 139 | exports.register.attributes = { 140 | name: 'routes-books' 141 | }; 142 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Hapi = require('hapi'); 4 | const mongojs = require('mongojs'); 5 | 6 | // Create a server with a host and port 7 | const server = new Hapi.Server(); 8 | server.connection({ 9 | host: 'localhost', 10 | port: 3000 11 | }); 12 | 13 | //Connect to db 14 | server.app.db = mongojs('hapi-rest-mongo', ['books']); 15 | 16 | //Load plugins and start server 17 | server.register([ 18 | require('./routes/books') 19 | ], (err) => { 20 | 21 | if (err) { 22 | throw err; 23 | } 24 | 25 | // Start the server 26 | server.start((err) => { 27 | console.log('Server running at:', server.info.uri); 28 | }); 29 | 30 | }); 31 | --------------------------------------------------------------------------------