├── .gitignore ├── .travis.yml ├── .DS_Store ├── snapshots ├── .DS_Store ├── get_using_self.png ├── post_location.png ├── get_using_mongoDB.png └── with_access_token.png ├── config.js ├── api ├── models │ ├── User.js │ └── geojson.js ├── routes │ └── routes.js └── controllers │ └── controller.js ├── package.json ├── server.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/divyanshu-rawat/haversine-rest-api/HEAD/.DS_Store -------------------------------------------------------------------------------- /snapshots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/divyanshu-rawat/haversine-rest-api/HEAD/snapshots/.DS_Store -------------------------------------------------------------------------------- /snapshots/get_using_self.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/divyanshu-rawat/haversine-rest-api/HEAD/snapshots/get_using_self.png -------------------------------------------------------------------------------- /snapshots/post_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/divyanshu-rawat/haversine-rest-api/HEAD/snapshots/post_location.png -------------------------------------------------------------------------------- /snapshots/get_using_mongoDB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/divyanshu-rawat/haversine-rest-api/HEAD/snapshots/get_using_mongoDB.png -------------------------------------------------------------------------------- /snapshots/with_access_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/divyanshu-rawat/haversine-rest-api/HEAD/snapshots/with_access_token.png -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = { 4 | 5 | 'secret': 'jwttokentesting', 6 | 'mongoUrl': 'mongodb://div:12345@ds031975.mlab.com:31975/redcarp' 7 | 8 | }; -------------------------------------------------------------------------------- /api/models/User.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var mongoose = require('mongoose'); 4 | var Schema = mongoose.Schema; 5 | 6 | 7 | module.exports = mongoose.model('User', new Schema({ 8 | username: String, 9 | password: String, 10 | admin: Boolean 11 | })); -------------------------------------------------------------------------------- /api/models/geojson.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | var mongoose = require('mongoose'); 5 | var Schema = mongoose.Schema; 6 | 7 | 8 | var DataSchema = new Schema({ 9 | properties: { 10 | name: { type: String, required: true } 11 | }, 12 | location: { 13 | type: { type: String, required: true }, 14 | coordinates: { type: [Number], index: '2dsphere'} 15 | } 16 | }); 17 | 18 | 19 | module.exports = mongoose.model('Geojson', DataSchema); 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "restapi", 3 | "version": "1.0.0", 4 | "description": "Restful application", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "keywords": [ 10 | "restapi", 11 | "testing" 12 | ], 13 | "author": "divyanshu rawat", 14 | "license": "ISC", 15 | "dependencies": { 16 | "body-parser": "^1.17.1", 17 | "express": "^4.15.2", 18 | "jsonwebtoken": "^8.0.1", 19 | "mongoose": "^4.9.8", 20 | "morgan": "^1.8.1" 21 | }, 22 | "devDependencies": { 23 | "nodemon": "^1.11.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | 4 | var mongoose = require('mongoose'); 5 | var bodyParser = require('body-parser'); 6 | var morgan = require('morgan') 7 | var jwt = require('jsonwebtoken'); 8 | var router = express.Router(); 9 | 10 | 11 | var port = process.env.PORT || 4000; 12 | var User = require('./api/models/User'); 13 | var Geojson = require('./api/models/geojson'); 14 | 15 | var config = require('./config'); 16 | 17 | 18 | mongoose.connect(config.mongoUrl); 19 | var db = mongoose.connection; 20 | db.on('error', console.error.bind(console, 'connection error:')); 21 | db.once('open', function () { 22 | 23 | console.log("Connected correctly to server"); 24 | 25 | }); 26 | 27 | // secret variable 28 | // app.set('secretKey', config.secret); 29 | 30 | app.use(bodyParser.urlencoded({ extended: true })); 31 | app.use(bodyParser.json()); 32 | 33 | // using morgan to log requests to the console 34 | app.use(morgan('dev')); 35 | 36 | app.use('/api', router); 37 | 38 | var routes = require('./api/routes/routes'); 39 | 40 | routes(router); 41 | 42 | app.use(function(req, res) { 43 | res.status(404).send({url: req.originalUrl + ' not found'}) 44 | }); 45 | 46 | 47 | app.set('port', (process.env.PORT || 5000)); 48 | 49 | app.listen(port); 50 | 51 | console.log('Server Started on Port: ' + port); 52 | 53 | // catch 404 and forward to error handler 54 | app.use(function(req, res, next) { 55 | var err = new Error('Not Found'); 56 | err.status = 404; 57 | next(err); 58 | }); -------------------------------------------------------------------------------- /api/routes/routes.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function(app){ 4 | 5 | 6 | var callback = require('../controllers/controller'); 7 | var config = require('../../config.js'); 8 | var jwt = require('jsonwebtoken'); 9 | 10 | app.post('/authenticate', callback.authenticate); 11 | app.post('/register',callback.register_user); 12 | 13 | // route middleware to verify a token 14 | 15 | // route middleware to verify a token 16 | 17 | app.use(function(req, res, next) { 18 | 19 | // check header or url parameters or post parameters for token 20 | var token = req.body.token || req.query.token || req.headers['x-access-token']; 21 | 22 | // decode token 23 | if (token) { 24 | 25 | // verifies secret and checks exp 26 | jwt.verify(token, config.secret, function(err, decoded) { 27 | if (err) { 28 | return res.json({ success: false, message: 'Failed to authenticate token.' }); 29 | } else { 30 | // if everything is good, save to request for use in other routes 31 | req.decoded = decoded; 32 | next(); 33 | } 34 | }); 35 | 36 | } else { 37 | 38 | // if there is no token 39 | // return an error 40 | return res.status(403).send({ 41 | success: false, 42 | message: 'No token provided.' 43 | }); 44 | 45 | } 46 | }); 47 | 48 | 49 | 50 | app.post('/post_location',callback.post_location); 51 | 52 | app.get('/get_location',callback.get_location); 53 | 54 | app.get('/',callback.basic_route); 55 | 56 | app.get('/users',callback.get_users); 57 | 58 | app.post('/get_using_self',callback.get_using_self); 59 | 60 | app.post('/get_using_mongodb',callback.get_using_mongodb); 61 | 62 | }; -------------------------------------------------------------------------------- /api/controllers/controller.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var mongoose = require('mongoose'); 4 | 5 | var User = mongoose.model('User'); 6 | var Geojson = mongoose.model('Geojson'); 7 | var jwt = require('jsonwebtoken'); 8 | var express = require('express'); 9 | var config = require('../../config.js'); 10 | 11 | var app = express(); 12 | 13 | exports.get_location = function(req,res){ 14 | 15 | Geojson.find({},function (err,location) { 16 | if(err) 17 | res.send(err) 18 | res.json(location); 19 | }); 20 | }; 21 | 22 | 23 | exports.post_location = function (req, res) { 24 | 25 | new Geojson({ 26 | 27 | properties: { 28 | name: req.body.name 29 | }, 30 | location: { 31 | type: "Point", 32 | coordinates:req.body.coordinates 33 | } 34 | }).save(function (err, result) { 35 | 36 | if(err) throw err; 37 | 38 | console.log(result); 39 | res.json(result); 40 | 41 | }); 42 | 43 | }; 44 | 45 | 46 | exports.basic_route = function (req,res) { 47 | res.json({ message: 'Welcome to the API !' }); 48 | } 49 | 50 | exports.register_user = function (req,res) { 51 | 52 | var newUser = new User({ 53 | 54 | username: req.body.username, 55 | password: req.body.password, 56 | admin: req.body.admin 57 | 58 | }); 59 | newUser.save(function(err,user) { 60 | 61 | if (err) throw err; 62 | console.log('User saved successfully'); 63 | res.json(user); 64 | 65 | }); 66 | 67 | } 68 | 69 | exports.get_users = function(req,res){ 70 | 71 | User.find({},function (err,user) { 72 | if(err) 73 | res.send(err) 74 | res.json(user); 75 | }); 76 | }; 77 | 78 | 79 | exports.authenticate = function(req, res) { 80 | 81 | // Finding User 82 | 83 | User.findOne({ 84 | username: req.body.username 85 | }, function(err, user) { 86 | 87 | console.log("found",user); 88 | 89 | if (err) throw err; 90 | 91 | if (!user) { 92 | 93 | res.json({ success: false, message: 'Authentication failed. User not found.' }); 94 | 95 | } 96 | else if (user) { 97 | 98 | // Checking User Password 99 | 100 | if (user.password != req.body.password) { 101 | 102 | 103 | res.json({ success: false, message: 'Authentication failed. Wrong password.' }); 104 | } 105 | else { 106 | 107 | // If User Is Found And Password Is Right 108 | // Create a JWT 109 | 110 | var token = jwt.sign({data: user}, config.secret, { 111 | 112 | expiresIn : 60*60*24 113 | // expires in 24 hours 114 | 115 | }); 116 | 117 | // return the information including token as JSON 118 | 119 | res.json({ 120 | success: true, 121 | message: 'JWT created Enjoy!', 122 | token: token 123 | }); 124 | } 125 | 126 | } 127 | 128 | }); 129 | 130 | }; 131 | 132 | 133 | exports.get_using_self = function (req,res) { 134 | 135 | Geojson.find({},function (err,response) { 136 | if(err) 137 | res.send(err) 138 | 139 | var updated_data = []; 140 | for (let value of response) { 141 | 142 | var distance = Haversine(req.body.coordinates[0],req.body.coordinates[1],value.location.coordinates[0],value.location.coordinates[1]); 143 | if(distance < req.body.radius) 144 | updated_data.push(value); 145 | } 146 | res.json(updated_data); 147 | 148 | }); 149 | 150 | } 151 | 152 | exports.get_using_mongodb = function (req,res) { 153 | 154 | 155 | var radius_in_Miles = req.body.radius * 0.621371; 156 | var coordinates = req.body.coordinates; 157 | 158 | Geojson.where('location') 159 | .within({ center: coordinates, radius: radius_in_Miles/3963.2 , unique: true, spherical: true }) 160 | .limit(10) 161 | .exec(function(err, result) { 162 | if(err) throw err; 163 | res.json(result); 164 | 165 | }); 166 | } 167 | 168 | 169 | // using the ‘Haversine’ formula to calculate distance between given (Latitude,longitude) pairs. 170 | 171 | function Haversine(lat1,lon1,lat2,lon2) { 172 | 173 | var R = 6371; // Radius of the earth in km 174 | var dLat = degree_to_radian(lat2-lat1); // deg2rad below 175 | var dLon = degree_to_radian(lon2-lon1); 176 | 177 | var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(degree_to_radian(lat1)) * Math.cos(degree_to_radian(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2); 178 | 179 | var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 180 | var d = R * c; // Distance in km 181 | return d; 182 | } 183 | 184 | function degree_to_radian(deg) { 185 | return deg * (Math.PI/180) 186 | } 187 | 188 | 189 | console.log('test); 190 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Built a rest Api in Node.js by leveraging Node.js 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/divyanshu-rawat/A-Rest-Api.svg)](https://greenkeeper.io/) 4 | 5 | ## 6 | [![forthebadge](https://forthebadge.com/images/badges/made-with-javascript.svg)](https://forthebadge.com) 7 | [![forthebadge](https://forthebadge.com/images/badges/check-it-out.svg)](https://forthebadge.com) 8 | [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com) 9 | 10 | 11 | [![Contact me on Codementor](https://cdn.codementor.io/badges/contact_me_github.svg)](https://www.codementor.io/divyanshurawat?utm_source=github&utm_medium=button&utm_term=divyanshurawat&utm_campaign=github) 12 | [![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/r46956) 13 | 14 | 15 | [![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/divyanshu-rawat) 16 | [![Build Status](https://travis-ci.org/divyanshu-rawat/JS-Testing.svg?branch=master)](https://travis-ci.org/divyanshu-rawat/JS-Testing) 17 | 18 | ## 19 | 20 | Back-End API 21 | 22 | * https://myrestfulapplication.herokuapp.com/api/users 23 | * Please Use POSTMAN for Testing Purpose !! 24 | * Authenticate Client First 25 | * Username : divyanshu 26 | * Password : xyz 27 | * A JWT will be generated and used for subsequent request from Client to server ! 28 | * You can register as well no need to rely on username : divyanshu !! 29 | 30 | ## 31 | 32 | #### Description 33 | * This Api compares results returned by ‘Haversine’ formula and MongoDB Geospatial Indexes and Queries feature. 34 | * when a location is given and we need to fetch all the nearby points within a radius. 35 | * Used JSON web tokens for token-based user authentication. 36 | * Used ‘Haversine’ formula to calculate distance between given (Latitude,longitude) pairs. 37 | * This Api compares results returned by ‘Haversine’ formula and MongoDB Geospatial Indexes and Queries feature. 38 | 39 | 40 | ## 41 | 42 | ### How it works ! 43 | #### Api Consist of following End Points 44 | 45 | ``` 46 | 47 | app.post('/post_location',callback.post_location); 48 | 49 | app.get('/get_location',callback.get_location); 50 | 51 | app.get('/',callback.basic_route); 52 | 53 | app.post('/register',callback.register_user); 54 | 55 | app.get('/users',callback.get_users); 56 | 57 | app.post('/get_using_self',callback.get_using_self); 58 | 59 | app.post('/get_using_self',callback.get_using_mongodb 60 | 61 | ``` 62 | 63 | 64 | ## 65 | 66 | #### Installation Instructions :grey_exclamation: 67 | 68 | * Clone or download the repo. into any fresh temporary folder. 69 | 70 | * Cd into that root folder you just cloned locally. 71 | 72 | * Open terminal in the current folder and to install all dependencies type 73 | 74 | ```javascript 75 | npm install 76 | ``` 77 | 78 | * Now typing 79 | 80 | ```javascript 81 | nodemon server.js 82 | ``` 83 | 84 | * will start a server ! 85 | 86 | ## 87 | 88 | #### DB Used (MongoDB) 89 | 90 | * MLab's MongoDB hosting platform is the fastest growing cloud Database-as-a-Service in the world. Get started with a free database and expert support. 91 | 92 | ## 93 | 94 | #### Package Manager Used (NPM) 95 | 96 | * NPM is the default package manager for the JavaScript runtime environment Node.js. 97 | 98 | ## 99 | 100 | #### Package.json (dependencies) 101 | 102 | * For dependencies refer Package.json. 103 | 104 | ## 105 | 106 | #### For Testing (Postman) 107 | 108 | * Postman extension can be used for testing ! 109 | * Supercharge your API workflow with Postman! Build, test, and document your APIs faster. 110 | * You can now fire up postman and then perform several operations on the REST API. 111 | 112 | ## 113 | 114 | ### Contributing 115 | 116 | 1. Create your **_branch_**: `git checkout -b my-new-feature` 117 | 118 | 2. **_Commit_** your changes: `git commit -m 'Add some feature'` 119 | 120 | 3. **_Push_** to the branch: `git push origin my-new-feature` 121 | 122 | 4. Send a **Pull Request** 123 | 124 | 5. **_Enjoy!_** 125 | 126 | ## 127 | 128 | 129 | Examples 130 | 131 | * GET Request to URL http://localhost:4000/api/get_location (with access token!) 132 | 133 | ![alt tag](https://github.com/divyanshu-rawat/task/blob/master/snapshots/with_access_token.png) 134 | 135 | 136 | ## 137 | 138 | * POST Request to URL https://myrestfulapplication.herokuapp.com/api/register (User Registration !) 139 | 140 | ![alt tag](https://github.com/divyanshu-rawat/A-Rest-Api/blob/master/snapshots/post_location.png) 141 | 142 | ## 143 | 144 | 145 | Comparison between Haversine Formula v/s Mongodb Geospatial 146 | 147 | * Sample Data via Postman 148 | 149 | ``` 150 | {"radius":"10","coordinates":[38.8,-77.0]} Data Format - [lat,long] 151 | ``` 152 | 153 | * POST Request to URL localhost:4000/api/get_using_self 154 | 155 | ![alt tag](https://github.com/divyanshu-rawat/task/blob/master/snapshots/get_using_self.png) 156 | 157 | ## 158 | 159 | * POST Request to URL localhost:4000/api/get_using_mongodb 160 | 161 | ![alt tag](https://github.com/divyanshu-rawat/task/blob/master/snapshots/get_using_mongoDB.png) 162 | 163 | ## 164 | --------------------------------------------------------------------------------