├── .gitignore ├── README.md ├── api └── v1 │ └── vacations.js ├── data └── vacations.js ├── db ├── settings.js └── vacations.js ├── index.js ├── models └── vacations.js ├── package.json └── tests └── TestDbOps.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 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 directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | 40 | credentials -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RETIRED - please DO NOT Use 2 | # Instead use the repository below 3 | https://github.com/acloudfan/REST-API-Course-V2 4 | 5 | Checkout the course on UDEMY: 6 | https://www.udemy.com/course/rest-api/?referralCode=ADE763DAA790A3F0D211 7 | 8 | 9 | Created as part of the course on "REST API". 10 | Demonstrates the setting up of URI for the REST API 11 | 12 | http://www.acloudfan.com/learn-REST-API 13 | 14 | 15 | Following node practices defined here: 16 | https://github.com/felixge/node-style-guide 17 | https://blog.risingstack.com/node-js-best-practices/ 18 | 19 | Recent Change - 12/25/2017 20 | * Data updated for the testing. 21 | ** Instead of providing the User/Password now the URI for DB is used in the format: 22 | 23 | mongodb://:@SERVER:PORT/DB-NAME 24 | 25 | 1. Clone this project on local file system 26 | 2. Pre-requisistes 27 | a. Understanding of node/npm 28 | b. An instance of MongoDB available either locally or remotely 29 | c. Import the data available in the repository 30 | 31 | 3. Run > npm install 32 | Deploys the packages 33 | express 34 | body-parser 35 | mongoose 36 | 37 | 38 | 39 | Create from scratch 40 | =================== 41 | 1. create the project 42 | 2. git init 43 | 3. add .gitignore 44 | 4. npm init 45 | 5. npm install the packages (express,body-parser,mongoose) 46 | 47 | 6. create folder = models 48 | -------------------------------------------------------------------------------- /api/v1/vacations.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains the definition of the API endpoints for vacation packages 3 | */ 4 | // As a best practice keep the resource name same as the file name 5 | var RESOURCE_NAME = 'vacations'; 6 | var VERSION = 'v1'; 7 | var URI = '/' + VERSION + '/' + RESOURCE_NAME; 8 | 9 | // Setup the vacations db 10 | var db = require('../../db/vacations') 11 | 12 | module.exports = function(router){ 13 | 'use strict'; 14 | 15 | // RETRIEVE all active vacation packages 16 | // Active = validTill >= Today's date 17 | 18 | // /v1/Vacations 19 | router.route(URI).get(function(req, res,next){ 20 | console.log("GET Vacations") 21 | //1. Setup query riteria for the active pacakages 22 | var criteria = {validTill : {$gte : new Date()}} 23 | 24 | //2. execute the query 25 | db.select(criteria, function(err,docs){ 26 | 27 | if(err){ 28 | console.log(err) 29 | res.status(500) 30 | res.send("Error connecting to db") 31 | } else { 32 | if(docs.length == 0){ 33 | res.status(404) 34 | } 35 | console.log("Retrieved vacations = %d",docs.length) 36 | res.send(docs) 37 | } 38 | }); 39 | }); 40 | 41 | // CREATE new vacation packages 42 | router.route(URI).post(function(req, res,next){ 43 | console.log("POST Vacations") 44 | 45 | //1. Get the data 46 | var doc = req.body; 47 | 48 | //2. Call the insert method 49 | db.save(doc, function(err,saved){ 50 | if(err){ 51 | // The returned error need to be defined better - in this example it is being left as is 52 | res.status(400).send(err) 53 | } else { 54 | res.send(saved) 55 | } 56 | }); 57 | }); 58 | } -------------------------------------------------------------------------------- /data/vacations.js: -------------------------------------------------------------------------------- 1 | 2 | exports.SingleRow = { 3 | "name":"BAHAMAS1000", 4 | "description":"4 Nights all paid Resort vacation in Bahamas at the Atlantis resort", 5 | "type": "resort", 6 | "destinations": [ 7 | { 8 | "city": "Nassau", 9 | "country": "Bahamas" 10 | } 11 | ], 12 | "includes": [ 13 | { 14 | "what": "hotel", 15 | "description": "King or Queen Bed room, can accomodate 2 Adults and 2 Children" 16 | }, 17 | { 18 | "what": "meals", 19 | "description": "Buffet style, available 24 hours in various resort restaurants" 20 | } 21 | ], 22 | "numberOfNights": 4, 23 | "pricePP": 300, 24 | "offer": { 25 | "discount": 0.1, 26 | "description": "End of year sale", 27 | "expires": "1/31/2020" 28 | }, 29 | "validTill": "1/31/2020", 30 | "soldout": false 31 | } 32 | 33 | exports.MultipleRows = [ 34 | { 35 | "name":"HAWAII1000", 36 | "description":"10 Nights all paid Resort vacation on Big Island", 37 | "type": "resort", 38 | "destinations": [ 39 | { 40 | "city": "Maui", 41 | "country": "Hawaii" 42 | } 43 | ], 44 | "includes": [ 45 | { 46 | "what": "hotel", 47 | "description": "King or Queen Bed room, can accomodate 2 Adults and 2 Children" 48 | }, 49 | { 50 | "what": "meals", 51 | "description": "Buffet style, available 24 hours in various resort restaurants" 52 | } 53 | ], 54 | "numberOfNights": 10, 55 | "pricePP": 800, 56 | "offer": { 57 | "discount": 0.25, 58 | "description": "End of year sale", 59 | "expires": "1/31/2020" 60 | }, 61 | "validTill": "1/31/2020", 62 | "soldout": false 63 | 64 | }, 65 | { 66 | "name":"CRUISEBAHAMAS1000", 67 | "description":"6 Nights cruise to Bahamas from Miami, FL in luxury line 'Carnival, Ocean Beauty'", 68 | "type": "cruise", 69 | "destinations": [ 70 | { 71 | "city": "Nassau", 72 | "country": "Bahamas" 73 | }, 74 | { 75 | "city": "Jamaica", 76 | "country": "Jamaica" 77 | } 78 | ], 79 | "includes": [ 80 | { 81 | "what": "cruise", 82 | "description": "Regular cruise suite can easily accomodate 2 adults and 2 children" 83 | }, 84 | { 85 | "what": "meals", 86 | "description": "Buffet style, available 24 hours in various restaurants" 87 | } 88 | ], 89 | "numberOfNights": 10, 90 | "pricePP": 800, 91 | "offer": { 92 | "discount": 0.25, 93 | "description": "End of year sale", 94 | "expires": "1/31/2020" 95 | }, 96 | "validTill": "1/31/2020", 97 | "soldout": false 98 | 99 | }] 100 | -------------------------------------------------------------------------------- /db/settings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * All database settings done in this file 3 | */ 4 | 5 | var mongoose = require('mongoose') 6 | // This would make mongoose use native Promises 7 | mongoose.Promise = global.Promise; 8 | 9 | // This environment property is used for getting the URI for MongoDB 10 | // 'mongodb://:@ds163387.mlab.com:63387/acme123' 11 | var uri = process.env.DB_URI 12 | 13 | // No need to provid ethe user /password separately its part of the URI 14 | // var options = {user:process.env.DB_USER, pass:process.env.DB_PASSWORD} 15 | 16 | mongoose.connect(process.env.DB_URI, { 17 | useMongoClient: true 18 | }); 19 | 20 | // Setup event listeners for the mongoose connections 21 | mongoose.connection.on('error', function(err){ 22 | console.log('Mongoose connection error') 23 | console.log(err) 24 | }) 25 | // events 26 | mongoose.connection.on('disconnected', function(){ 27 | console.log('Mongoose disconnected') 28 | }) 29 | mongoose.connection.on('open', function(){ 30 | console.log('Mongoose connected') 31 | }) 32 | 33 | // export the mongoose & db 34 | exports.mongoose = mongoose; 35 | exports.db = mongoose.connection; 36 | 37 | -------------------------------------------------------------------------------- /db/vacations.js: -------------------------------------------------------------------------------- 1 | /** 2 | * All database operations related to the vacations collection will reside in this file 3 | */ 4 | var model = require('../models/vacations') 5 | var settings = require('../db/settings') 6 | 7 | // CREATE the vacation package 8 | exports.save = function (data, callback) { 9 | 10 | new model.Vacations(data).save(function (err, inserted) { 11 | callback(err, inserted) 12 | 13 | }) 14 | } 15 | 16 | // CREATE multiple vacation packages 17 | exports.saveMany = function (rows, callback) { 18 | 19 | model.Vacations.insertMany(rows, function (err, docs) { 20 | callback(err, docs) 21 | }) 22 | 23 | } 24 | 25 | // UPDATE the vacation packages 26 | // http://mongoosejs.com/docs/api.html#model_Model.update 27 | exports.update = function (criteria, doc, callback) { 28 | model.Vacations.update(criteria, doc, function (err, data) { 29 | callback(err, data) 30 | 31 | }) 32 | } 33 | 34 | // RETRIEVE vacation packages based on criteria 35 | exports.select = function (criteria, callback) { 36 | model.Vacations.find(criteria, function (err, data) { 37 | callback(err, data) 38 | }) 39 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Provide the URI in the right format 4 | process.env.DB_URI = "mongodb://:@SERVER:PORT/DB-NAME" 5 | 6 | // Following 2 are not needes as the user/password are part of the URI 7 | //process.env.DB_USER = "set this up" /**provide the user id */ 8 | //process.env.DB_PASSWORD = "set this up" /**provide the password */ 9 | 10 | var express = require('express') 11 | var bodyParser = require('body-parser') 12 | 13 | var router = express.Router(); 14 | require('./api/v1/vacations')(router); 15 | 16 | // Create the express app 17 | app = express(); 18 | // Setup the body parser 19 | //app.use(bodyParser.urlencoded({extended: true})); 20 | app.use(bodyParser.json());//{type: '*/*'})); 21 | 22 | // Setup the app to use the router 23 | app.use(router); 24 | 25 | // Start the listener 26 | app.listen(3000); 27 | console.log('Listening on 3000') 28 | 29 | -------------------------------------------------------------------------------- /models/vacations.js: -------------------------------------------------------------------------------- 1 | /** 2 | * "REST API Course" 3 | * 4 | * Model for the ACME vacation package. 5 | */ 6 | 7 | var settings = require('../db/settings') 8 | 9 | 10 | var VacationsSchema = settings.mongoose.Schema( 11 | { 12 | // Name of the vacation package - BAHAMAS1000 - primary Key 13 | name: {type:String, required:[true,'name is needed']}, 14 | description : {type:String, required:true}, 15 | // ACME offers resorts & cruise vacation package 16 | type: {type:String, enum:['resort','cruise']}, 17 | // Destination city 18 | destinations : [{city:String, country:String}], 19 | // Includes - what all does the package Include 20 | includes : [{ 21 | what:{type:String, enum:['flight', 'meals','cruise','hotel','rentalcar','excursions','misc']}, 22 | description:{type:String, required:false} 23 | }], 24 | numberOfNights:{type: Number, required:true, min:1, max:31}, 25 | // Price per person 26 | pricePP: Number, 27 | // Special offers 28 | offer : { 29 | discount: Number, 30 | description : String, 31 | expires:{type:Date, required:false} 32 | }, 33 | // Till what date is the package valid 34 | validTill:{type:Date, required:true}, 35 | // Package may get sold out 36 | soldout: {type:Boolean, required:true, default:false}, 37 | // Link to pictures 38 | pictures:{type:[String]} 39 | } 40 | ); 41 | 42 | // Export the model 43 | exports.Vacations = settings.mongoose.model('vacation', VacationsSchema) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uridemo", 3 | "version": "1.0.0", 4 | "description": "This is part of the course on \"REST API Development\"", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/rajrin/URIDemo.git" 12 | }, 13 | "keywords": [ 14 | "rest", 15 | "api", 16 | "architecture", 17 | "constraints" 18 | ], 19 | "author": "acloudfan.com", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/rajrin/URIDemo/issues" 23 | }, 24 | "homepage": "https://github.com/rajrin/URIDemo#readme", 25 | "dependencies": { 26 | "body-parser": "^1.15.2", 27 | "express": "^4.14.0", 28 | "mongoose": "^4.6.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/TestDbOps.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple tests for all DB tests 3 | * 4 | * Adds the test data to the collection 5 | */ 6 | 7 | 8 | // This is the old way which is not accepted by API anymore 9 | // This is what you have seen in he video - please use the process.env.DB_URI 10 | //process.env.DB_USER = "test";// 11 | //process.env.DB_PASSWORD = "test";//acloudfan" 12 | 13 | // Provide the URI in the right format 14 | process.env.DB_URI = "mongodb://:@SERVER:PORT/DB-NAME" 15 | 16 | //Test#1 Insert the Vacation data 17 | var db = require('../db/vacations') 18 | var data = require('../data/vacations') 19 | 20 | 21 | // Save a single row 22 | db.save(data.SingleRow,function(err, saved){ 23 | if(err){ 24 | console.log("Failed single row save") 25 | //console.log(err) 26 | //process.exit(1) 27 | } else { 28 | console.log("Success - Save single row - %s",saved.name) 29 | } 30 | }); 31 | 32 | // Save multiple rows 33 | db.saveMany(data.MultipleRows,function(err, docs){ 34 | if(err){ 35 | console.log("Failed multiple row insert") 36 | //console.log(err) 37 | //process.exit(1) 38 | } else { 39 | console.log("Success - Multiple rows inserted - %d",docs.length) 40 | } 41 | }); 42 | 43 | // Select vacations with some criteria 44 | var selectCriteria = {validTill : {$gt : new Date()}} 45 | db.select(selectCriteria, function(err, data){ 46 | if(err){ 47 | console.log("Failed to get vacations : %s",criteria) 48 | console.log(err) 49 | } else { 50 | console.log("Successfully selected %d documents for %s", data.length, JSON.stringify(selectCriteria)) 51 | } 52 | }); 53 | 54 | // Update the vacations 55 | var updateCriteria = {name:'BAHAMAS1000'} 56 | var doc = {description:'UPDATED Desc for TESTING'} 57 | db.update(updateCriteria,doc,function(err, doc){ 58 | if(err){ 59 | console.log("Failed to get update") 60 | console.log(err) 61 | } else { 62 | console.log("Successfully updated with criteria %s", updateCriteria) 63 | } 64 | }) 65 | --------------------------------------------------------------------------------