├── .data ├── test │ └── newfile.json └── users │ └── kyoberonald@gmail.com.json ├── README.md ├── https ├── keyGeneration.txt ├── cert.pem └── key.pem ├── package.json ├── lib ├── helpers.js ├── config.js ├── data.js └── handlers.js └── index.js /.data/test/newfile.json: -------------------------------------------------------------------------------- 1 | {"fizz":"buzz"} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rest-Api-Node 2 | Build a node API using Node (without using a framework) 3 | -------------------------------------------------------------------------------- /https/keyGeneration.txt: -------------------------------------------------------------------------------- 1 | openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem 2 | -------------------------------------------------------------------------------- /.data/users/kyoberonald@gmail.com.json: -------------------------------------------------------------------------------- 1 | {"firstName":"Ronald","lastName":"cyobe","email":"kyoberonald@gmail.com","country":"Uganda","age":"27"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rest-api-node", 3 | "version": "1.0.0", 4 | "description": "Node API", 5 | "main": "index.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "start": "node index.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/kyobero/Rest-Api-Node.git" 16 | }, 17 | "keywords": [ 18 | "heroku" 19 | ], 20 | "author": "Ronald k", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/kyobero/Rest-Api-Node/issues" 24 | }, 25 | "homepage": "https://github.com/kyobero/Rest-Api-Node#readme" 26 | } 27 | -------------------------------------------------------------------------------- /lib/helpers.js: -------------------------------------------------------------------------------- 1 | /* 2 | *Helpers for the various tasks 3 | * 4 | */ 5 | 6 | // Dependencies 7 | var config = require('./config'); 8 | var crypto = require('crypto'); 9 | 10 | //Container for all the Helpers 11 | 12 | var helpers = {}; 13 | 14 | // Create a SHA256 hash 15 | helpers.hash = function(str){ 16 | if(typeof(str) == 'string' && str.length > 0){ 17 | var hash = crypto.createHmac('sha256', config.hashingSecret).update(str).digest('hex'); 18 | return hash; 19 | } else { 20 | return false; 21 | } 22 | }; 23 | 24 | // parse a Json string to an object in all cases, without throwing 25 | helpers.parseJsonToObject = function (str){ 26 | try{ 27 | var obj = JSON.parse(str); 28 | return obj; 29 | }catch(e){ 30 | return {}; 31 | } 32 | }; 33 | 34 | 35 | 36 | 37 | //Export the module 38 | module.exports = helpers; 39 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Create and export configuration variables 3 | * 4 | */ 5 | 6 | // Container for all environments 7 | var environments = {}; 8 | 9 | // Staging (default) environment 10 | environments.staging = { 11 | 'httpPort' : 3000, 12 | 'httpsPort' : 3001, 13 | 'envName' : 'staging', 14 | 'hashingSecret':'thisIsASecret' 15 | }; 16 | 17 | // Production environment 18 | environments.production = { 19 | 'httpPort' : 5000, 20 | 'httpsPort' : 5001, 21 | 'envName' : 'production', 22 | 'hashingSecret' : 'thisIsAlsoASecret' 23 | }; 24 | 25 | // Determine which environment was passed as a command-line argument 26 | var currentEnvironment = typeof(process.env.NODE_ENV) == 'string' ? process.env.NODE_ENV.toLowerCase() : ''; 27 | 28 | // Check that the current environment is one of the environments above, if not default to staging 29 | var environmentToExport = typeof(environments[currentEnvironment]) == 'object' ? environments[currentEnvironment] : environments.staging; 30 | 31 | // Export the module 32 | module.exports = environmentToExport; 33 | -------------------------------------------------------------------------------- /https/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID6TCCAtGgAwIBAgIUcpOR9iRqzAbSB7HrclvhWbvlPUMwDQYJKoZIhvcNAQEL 3 | BQAwgYMxCzAJBgNVBAYTAkdIMQ4wDAYDVQQIDAVBY2NyYTEOMAwGA1UEBwwFQWNj 4 | cmExDTALBgNVBAoMBE1lc3QxCzAJBgNVBAsMAklUMRIwEAYDVQQDDAlsb2NhbGhv 5 | c3QxJDAiBgkqhkiG9w0BCQEWFWt5b2Jlcm9uYWxkQGdtYWlsLmNvbTAeFw0yMDAx 6 | MTExMzA5MzJaFw0zMDAxMDgxMzA5MzJaMIGDMQswCQYDVQQGEwJHSDEOMAwGA1UE 7 | CAwFQWNjcmExDjAMBgNVBAcMBUFjY3JhMQ0wCwYDVQQKDARNZXN0MQswCQYDVQQL 8 | DAJJVDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVreW9iZXJv 9 | bmFsZEBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQ 10 | DZOWi2/KDQs5AVweZ5N7P2IoK9iGJY9JELl7aSsPUvufUEoBgOd6nVwT8VnbACOD 11 | mJAEDn1N0RjBelyY5B3NldL9roWMOx7XLgLzQsRavxXEHLZOtWkyJudDcRpdaU9W 12 | 8gbRpt2ABoJs0D7qv7hIq1vXBxHSqLAOLbHMRKWSIpCJq7IKZS8+2OKtGIYbvr4M 13 | /br07u3Wg1ioBnd2gAgQrugZlouQwjW8HisZUNLcnBrqRCx7Ur19IKjquguVlG6H 14 | bBX9MuYHdPQetFtsdig+3v0GMoWN7yVlVsueL/47JQRNzR8LtSYp9z+av6cNTeum 15 | XnMkPhLPxe4qGIg+e2P1AgMBAAGjUzBRMB0GA1UdDgQWBBQSjZLgXNICxkE/zp51 16 | 6k07FaulUjAfBgNVHSMEGDAWgBQSjZLgXNICxkE/zp516k07FaulUjAPBgNVHRMB 17 | Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBDKuVvDdYhzrnEtcnSEmzFlEOR 18 | 6aWTD0bkgpO9WKnO3s33L0ddc8xfbv+ohIFrWI9fcUkcNKGeBkCLhK0QJPA4HN1j 19 | 3HlD7Uwzkmwz2T9Mz4I+aPeg2oXuQHtwvIJfwf0I5WexkjkagHfDseQ6pWyb6ClJ 20 | BkmlBdXbBP7CKBbUo9Q8U66jl7bU6WiWm62uFMvHvITz9Mcn1u3hQOOScDPx+mAO 21 | ugnhC7ce3Z2V3t8zzisQs0ii1hQ8P2VEMuN1mVC5SWIUDBc1f1kA96iXoU1QI+h6 22 | NjqTvbBuTt51ZAwd8EhQNR8vWBtpOr/z522HBsTRD9TDd6Wifc4XC2iVxWZZ 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /https/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDQDZOWi2/KDQs5 3 | AVweZ5N7P2IoK9iGJY9JELl7aSsPUvufUEoBgOd6nVwT8VnbACODmJAEDn1N0RjB 4 | elyY5B3NldL9roWMOx7XLgLzQsRavxXEHLZOtWkyJudDcRpdaU9W8gbRpt2ABoJs 5 | 0D7qv7hIq1vXBxHSqLAOLbHMRKWSIpCJq7IKZS8+2OKtGIYbvr4M/br07u3Wg1io 6 | Bnd2gAgQrugZlouQwjW8HisZUNLcnBrqRCx7Ur19IKjquguVlG6HbBX9MuYHdPQe 7 | tFtsdig+3v0GMoWN7yVlVsueL/47JQRNzR8LtSYp9z+av6cNTeumXnMkPhLPxe4q 8 | GIg+e2P1AgMBAAECggEAOxAvnuRUxwpu7i75pNQIpUt4JSlVXbfZ9ocd8PAJPl9z 9 | eWXErKqYjFGR60NwG+DtNBWihNRMNEQw//Qpx2mzIELxU/0wgn/iIHo6ci65KX3n 10 | wvXXt35+r7MlohrAvlYAJRGuZ+Q0K30tl5CC3AezXEXxW5jxMVmcKVpFiFTQoCxW 11 | x0XDpZCuhiaSvCiYKO8Dgn/QmagtAixkjSaswVyS5RZ8hLjvbIgxvmihjNdE9huH 12 | XH81souTIqMj2hs9K8Sblm+XEMlgns34XRk12UKOsA230RXn4VI6H3zY7zj/TEpt 13 | GOECrfnA6/A4xod13x0ltCE6L282uc7Rj/ZYIUNDgQKBgQDrJFc7sVLwmswKnPTr 14 | 9R3R++puVy6LdEXTx2FdP89BRsgKXcyK2RBr15oIERtnov6UMZgPleG1bw8QeKOF 15 | 4np8deOsya6mPm0eLXnk020wRsSxucG+sf78zHb94BUT6g5AMMO7gofPt2tn+bcJ 16 | mVE/2soyX3+tAIQLbhhwTxGY4QKBgQDighgV7cu5i452W9q55q9H/QztWd0wJGJ+ 17 | yclxcyyAJpwWXaOAQ5FIylqOM0BqZPAiH6DsbI72msyxmFa8M6zoktu0nPqa2EEo 18 | DzsAKUXXqqhE2RUqNxFCJyZ+1FsHTfghrOu6mAugswI4pwQRnmFoncmi72g+6Rc2 19 | LSzvaw2JlQKBgF5aCarJH2euJXuIuXpIs7uDYvD9iI6qjC5LTZU2OnqN5UzLkHyS 20 | VtV/AK6F9sIiFBbww3xVfujndFr+nVbmppF0WHQHxU2ttOksBEI+WAzMCLbru4NC 21 | NvfHL2P1W1/PRgKZzqBZ4xcFGVLyT3DJlWGS8BlAWqHXmCRh++psv7nhAoGALp0V 22 | NdYVGd8Vd1gZ4C4QHmF+Oo5GzbR/LJZ8RUOtgcXwU0376tZ83J0AG8mCVSLmpC8c 23 | H+uLVEaxH085cku0JryqSDYSALHGXucbfkIAJIzzSg/eoixo+dMyweETxqIOEWgT 24 | rvfBVNXh/CSq2rFcXHo0V7qrGl8/rp+HYtIGHC0CgYEAo7sHcP8T7dAvJp1pMt+a 25 | f450TagC0GhMuF9QY78d9lbZ14MadZVnXa2ogSaDIv/1E2LGDHwBIzQlf2jLX5wO 26 | HY08Igci9wLt/PXLklfr37rIaIREKEzEJz9jPxJ1EgnbRawyN2RbPaPc1iIZkNWV 27 | 8OmZUtkgBlteAK2s6v+XvV8= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /lib/data.js: -------------------------------------------------------------------------------- 1 | /* 2 | *libray for storing and editing data 3 | */ 4 | 5 | //Dependancies 6 | var fs = require('fs'); 7 | var path = require ('path'); 8 | var helpers = require('./helpers'); 9 | 10 | //container for the module (to be exported) 11 | 12 | var lib = {}; 13 | 14 | //Base directory of the data folder 15 | lib.baseDir = path.join(__dirname,'/../.data/'); 16 | //lib.baseDir = path.join(_dirname,'/../.data'); 17 | 18 | // write data to a file 19 | lib.create = function (dir, file,data,callback){ 20 | //open the file for writing 21 | fs.open(lib.baseDir+dir+'/'+file+'.json','wx',function(err,fileDescriptor){ 22 | if(!err && fileDescriptor){ 23 | 24 | //Convert Data to string 25 | var stringData = JSON.stringify(data); 26 | // callback(false); 27 | 28 | fs.writeFile(fileDescriptor,stringData,function(err){ 29 | if (!err){ 30 | //callback(false); 31 | fs.close(fileDescriptor,function(err){ 32 | if(!err){ 33 | callback(false); 34 | }else{ 35 | callback( 'Error closing new file' ); 36 | } 37 | }); 38 | } else{ 39 | callback('Error writing to new file'); 40 | } 41 | }); 42 | } else{ 43 | callback('Could not create new file, it may already exist'); 44 | } 45 | 46 | }); 47 | }; 48 | 49 | //Read data from a file 50 | 51 | lib.read = function(dir,file,callback){ 52 | fs.readFile(lib.baseDir+dir+'/'+file+'.json','utf8',function(err,data){ 53 | if(!err && data){ 54 | var parsedData = helpers.parseJsonToObject(data); 55 | callback(false,parsedData); 56 | } else { 57 | callback(err,data); 58 | } 59 | }); 60 | }; 61 | 62 | //Update data inside a file 63 | 64 | lib.update = function(dir,file,data,callback){ 65 | fs.open(lib.baseDir+dir+'/'+file+'.json','r+',function(err,fileDescriptor){ 66 | if(!err && fileDescriptor){ 67 | //convert data to string 68 | var stringData = JSON.stringify(data); 69 | 70 | //Truncate the the file 71 | fs.truncate(fileDescriptor,function(error){ 72 | if(!err){ 73 | //Write to the file and close it 74 | fs.writeFile(fileDescriptor,stringData,function(error){ 75 | if(!err){ 76 | fs.close(fileDescriptor,function(err){ 77 | if(!err){ 78 | callback(false); 79 | }else{ 80 | callback('Error closing existing file'); 81 | } 82 | }); 83 | }else{ 84 | callback('Error writing to existing file'); 85 | } 86 | }); 87 | } else { 88 | callback ('Error truncating file') 89 | } 90 | }); 91 | } 92 | })}; 93 | 94 | 95 | // Delete a file 96 | lib.delete = function(dir,file,callback){ 97 | 98 | // Unlink the file from the filesystem 99 | fs.unlink(lib.baseDir+dir+'/'+file+'.json', function(err){ 100 | callback(err); 101 | }); 102 | 103 | }; 104 | 105 | lib.list = function (dir,callback){ 106 | //Reads the list of user emails 107 | fs.readdir(lib.baseDir+dir, function(err,data){ 108 | if (!err && data){ 109 | var arrData = []; 110 | data.forEach(fileName => { 111 | arrData.push(fileName.replace('.json', '')) 112 | }) 113 | return callback(false, arrData) ; 114 | }else{ 115 | console.log(err) 116 | } 117 | }) 118 | } 119 | 120 | 121 | module.exports = lib; 122 | 123 | 124 | /** 125 | * Library to store and edit data 126 | */ 127 | 128 | // const fs = require('fs'); 129 | // const path = require('path'); 130 | 131 | // const create = (dir, file, data, callback) => { 132 | // fs.open(resolvePath(dir, file), 'wx', (err, fileDescriptor) => { 133 | // if (!err && fileDescriptor) { 134 | // const stringData = JSON.stringify(data); 135 | 136 | // fs.writeFile(fileDescriptor, stringData, err => { 137 | // if (err) return callback(err); 138 | 139 | // fs.close(fileDescriptor, err => { 140 | // if (err) return callback(err); 141 | // callback(false); 142 | // }) 143 | // }); 144 | // } else { 145 | // callback(err) 146 | // } 147 | // }); 148 | // }; 149 | 150 | // const read = (dir, file, callback) => { 151 | // fs.readFile(resolvePath(dir, file), 'utf8', (err, data) => { 152 | // if (err) return callback(err); 153 | // callback(undefined, JSON.parse(data)); 154 | // }); 155 | // }; 156 | 157 | // const update = (dir, file, data, callback) => { 158 | // fs.open(resolvePath(dir, file), 'r+', (err, fileDescriptor) => { 159 | // if (!err && fileDescriptor) { 160 | // const stringData = JSON.stringify(data); 161 | 162 | // // fs.truncate(fileDescriptor, err => { 163 | // // if (err) return callback(err); 164 | 165 | // // In the tutorial, `fs.truncate` was called before writing to the file with `fs.writeFile`. 166 | // // I however noticed that `fs.truncate` is not needed. The default flag for `fs.writeFile` is `w` 167 | // // and what it does is creates the file (if it does not exist) or truncates it (if it exists). 168 | // // Check https://nodejs.org/api/fs.html#fs_file_system_flags for more information 169 | // fs.writeFile(fileDescriptor, stringData, err => { 170 | // if (err) return callback(err); 171 | 172 | // fs.close(fileDescriptor, err => { 173 | // if (err) return callback(err); 174 | // callback(); 175 | // }) 176 | // }); 177 | // // }) 178 | // } else { 179 | // callback(err) 180 | // } 181 | // }); 182 | // }; 183 | 184 | // const deleteFile = (dir, file, callback) => { 185 | // fs.unlink(resolvePath(dir, file), err => { 186 | // if (err) return callback(err); 187 | // callback(); 188 | // }); 189 | // } 190 | 191 | // const resolvePath = (dir, file) => `${path.join(__dirname, '../.data')}/${dir}/${file}.json`; 192 | 193 | // module.exports = { create, read, update, deleteFile }; 194 | 195 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Primary file for API 3 | * 4 | */ 5 | 6 | // Dependencies 7 | var http = require('http'); 8 | var https = require('https'); 9 | var url = require('url'); 10 | var StringDecoder = require('string_decoder').StringDecoder; 11 | var config = require('./lib/config'); 12 | var fs = require('fs'); 13 | var _data = require('./lib/data'); 14 | var handlers = require('./lib/handlers'); 15 | var helpers = require('./lib/helpers'); 16 | 17 | 18 | // //Testing 19 | // //@TODO 20 | // _data.delete('test','newfile',function(err){ 21 | // console.log('This was the error', err); 22 | // }); 23 | 24 | // Instantiate the HTTP server 25 | var httpServer = http.createServer(function(req,res){ 26 | unifiedServer(req,res); 27 | }); 28 | 29 | 30 | // Start the HTTP server 31 | var PORT = process.env.PORT || config.httpPort; 32 | 33 | httpServer.listen(PORT,function(){ 34 | console.log('The HTTP server is running on port '+config.httpPort); 35 | }); 36 | 37 | // Instantiate the HTTPS server 38 | var httpsServerOptions = { 39 | 'key': fs.readFileSync('./https/key.pem'), 40 | 'cert': fs.readFileSync('./https/cert.pem') 41 | }; 42 | var httpsServer = https.createServer(httpsServerOptions,function(req,res){ 43 | unifiedServer(req,res); 44 | }); 45 | 46 | // Start the HTTPS server 47 | httpsServer.listen(config.httpsPort,function(){ 48 | console.log('The HTTPS server is running on port '+config.httpsPort); 49 | }); 50 | 51 | // All the server logic for both the http and https server 52 | var unifiedServer = function(req,res){ 53 | 54 | // Parse the url 55 | var parsedUrl = url.parse(req.url, true); 56 | 57 | // Get the path 58 | var path = parsedUrl.pathname; 59 | var trimmedPath = path.replace(/^\/+|\/+$/g, ''); 60 | 61 | // Get the query string as an object 62 | var queryStringObject = parsedUrl.query; 63 | 64 | // Get the HTTP method 65 | var method = req.method.toLowerCase(); 66 | 67 | //Get the headers as an object 68 | var headers = req.headers; 69 | 70 | // Get the payload,if any 71 | var decoder = new StringDecoder('utf-8'); 72 | var buffer = ''; 73 | req.on('data', function(data) { 74 | buffer += decoder.write(data); 75 | }); 76 | req.on('end', function() { 77 | buffer += decoder.end(); 78 | 79 | // Check the router for a matching path for a handler. If one is not found, use the notFound handler instead. 80 | var chosenHandler = typeof(router[trimmedPath]) !== 'undefined' ? router[trimmedPath] : handlers.notFound; 81 | 82 | // Construct the data object to send to the handler 83 | var data = { 84 | 'trimmedPath' : trimmedPath, 85 | 'queryStringObject' : queryStringObject, 86 | 'method' : method, 87 | 'headers' : headers, 88 | 'payload' : helpers.parseJsonToObject(buffer) 89 | }; 90 | 91 | // Route the request to the handler specified in the router 92 | chosenHandler(data,function(statusCode,payload){ 93 | 94 | // Use the status code returned from the handler, or set the default status code to 200 95 | statusCode = typeof(statusCode) == 'number' ? statusCode : 200; 96 | 97 | // Use the payload returned from the handler, or set the default payload to an empty object 98 | payload = typeof(payload) == 'object'? payload : {}; 99 | 100 | // Convert the payload to a string 101 | var payloadString = JSON.stringify(payload); 102 | 103 | // Return the response 104 | res.setHeader('Content-Type', 'application/json'); 105 | res.writeHead(statusCode); 106 | res.end(payloadString); 107 | console.log(trimmedPath,statusCode); 108 | }); 109 | 110 | }); 111 | }; 112 | 113 | 114 | // Define the request router 115 | var router = { 116 | 'ping' : handlers.ping, 117 | // 'users':handlers.users, 118 | '': handlers.eit 119 | }; 120 | 121 | 122 | 123 | // const fs = require('fs'); 124 | // const url = require('url'); 125 | // const http = require('http'); 126 | // const https = require('https'); 127 | // const { StringDecoder } = require('string_decoder'); 128 | 129 | // const requestHandler = (req, res) => { 130 | // // Get the URL and parse it 131 | // const parsedUrl = url.parse(req.url, true); 132 | 133 | // // Get the path 134 | // const path = parsedUrl.pathname; 135 | // const trimmedPath = path.replace(/^\/+|\/+$/g, ''); 136 | 137 | // // Get the query string as an object 138 | // const queryStringObject = parsedUrl.query; 139 | 140 | // // Get the HTTP method 141 | // const method = req.method.toLowerCase(); 142 | 143 | // // Get the headers as an object 144 | // const headers = req.headers; 145 | 146 | // // Required to decode the streams of data 147 | // // from the HTTP request into string 148 | // const decoder = new StringDecoder('utf-8'); 149 | // let buffer = ''; 150 | 151 | // // A "data" event is emmited each time a stream is received 152 | // req.on('data', data => { 153 | // buffer += decoder.write(data) 154 | // }); 155 | 156 | // // After all streams have been received, an "end" event is emmited 157 | // req.on('end', () => { 158 | // buffer += decoder.end() 159 | // const handler = typeof(router[trimmedPath]) == 'undefined' ? handlers.notFound : router[trimmedPath]; 160 | 161 | // const data = { 162 | // path, 163 | // method, 164 | // headers, 165 | // trimmedPath, 166 | // queryStringObject, 167 | // payload: buffer, 168 | // }; 169 | 170 | // handler(data, (statusCode, payload) => { 171 | // statusCode = typeof(statusCode) == 'number' ? statusCode : 200; 172 | // payload = JSON.stringify(typeof(payload) == 'object' ? payload : {}); 173 | 174 | // res.writeHead(statusCode, { 175 | // 'Content-Type': 'application/json' 176 | // }); 177 | 178 | // // We could also set the header by using setHeader 179 | // // res.setHeader('Content-Type', 'application/json'); 180 | 181 | // res.end(payload); 182 | 183 | // console.log('Returning response: ', statusCode, payload); 184 | // }); 185 | 186 | // }); 187 | // } 188 | 189 | // const httpServer = http.createServer(requestHandler); 190 | 191 | // const httpsOptions = { 192 | // key: fs.readFileSync('./https/key.pem'), 193 | // cert: fs.readFileSync('./https/cert.pem') 194 | // }; 195 | 196 | // const httpsServer = https.createServer(httpsOptions, requestHandler); 197 | 198 | // httpServer.listen(3000, () => { 199 | // console.log('HTTP server listening on port 3000!'); 200 | // }); 201 | 202 | // httpsServer.listen(3001, () => { 203 | // console.log('HTTPS server listening on port 3001!'); 204 | // }); 205 | 206 | // const handlers = { 207 | // sample(data, callback) { 208 | // callback(200, {name: 'sample handler'}) 209 | // }, 210 | 211 | // notFound(data, callback) { 212 | // callback(404) 213 | // } 214 | // } 215 | 216 | // const router = { 217 | // sample: handlers.sample 218 | // }; 219 | -------------------------------------------------------------------------------- /lib/handlers.js: -------------------------------------------------------------------------------- 1 | /* 2 | *Request handlers 3 | * 4 | */ 5 | 6 | // Dependancies 7 | var _data = require('./data'); 8 | var helpers = require('./helpers.js'); 9 | 10 | 11 | // Define all the handlers 12 | var handlers = {}; 13 | 14 | handlers.eit = function(data,callback){ 15 | var acceptableMethods = ['post','get','put','delete']; 16 | if(acceptableMethods.indexOf(data.method) > -1){ 17 | handlers._eit[data.method](data,callback); 18 | }else{ 19 | callback(405); 20 | } 21 | }; 22 | 23 | //containers for the users submethods 24 | handlers._eit = {}; 25 | 26 | //Users-post 27 | //Required data: firstName, lastName, phone, password, tosAgreement 28 | //Optional data:none 29 | handlers._eit.post = function(data,callback){ 30 | //Check that all the required data fields are filled out 31 | var firstName = typeof(data.payload.firstName) == 'string' && data.payload.firstName.trim().length > 0 ? data.payload.firstName.trim() : false; 32 | var lastName = typeof(data.payload.lastName) == 'string' && data.payload.lastName.trim().length > 0 ? data.payload.lastName.trim() : false; 33 | var email = typeof(data.payload.email) == 'string' && data.payload.email.trim().length > 0 ? data.payload.email.trim() : false; 34 | var country = typeof(data.payload.country) == 'string' && data.payload.country.trim().length > 0 ? data.payload.country.trim() : false; 35 | var age = typeof(data.payload.age) == 'string' && data.payload.age.trim().length > 0 ? data.payload.age.trim() : false; 36 | //var tosAgreement = typeof(data.payload.tosAgreement) == 'boolean' && data.payload.tosAgreement == true ? true : false; 37 | 38 | if(firstName && lastName && email && country && age){ 39 | //Make sure that the user doesn't already exist 40 | _data.read('users',email,function(err,data){ 41 | if(err){ 42 | // //Hash the password 43 | // var hashedPassword = helpers.hash(password); 44 | 45 | // // Create the user object 46 | // if(hashedPassword){ 47 | var userObject = { 48 | 'firstName' : firstName, 49 | 'lastName' : lastName, 50 | 'email' : email, 51 | 'country' : country, 52 | 'age' : age 53 | //'tosAgreement' : true 54 | }; 55 | 56 | // Store the user 57 | _data.create('users',email,userObject,function(err){ 58 | if(!err){ 59 | callback(200); 60 | } else { 61 | console.log(err); 62 | callback(500,{'Error' : 'Could not create the new user'}); 63 | } 64 | }); 65 | // } else { 66 | // callback(500,{'Error' : 'Could not hash the user\'s password.'}); 67 | // } 68 | 69 | }else{ 70 | //User already existis 71 | callback(400, {'Error': 'A user with that phone number already exists'}); 72 | } 73 | }); 74 | } else { 75 | callback(400,{'Error' : 'Missing required fields'}); 76 | } 77 | }; 78 | 79 | // Required data: phone 80 | // Optional data: none 81 | // @TODO Only let an authenticated user access their object. Dont let them access anyone elses. 82 | handlers._eit.get = function(data,callback){ 83 | // Check that phone number is valid 84 | var email = typeof(data.queryStringObject.email) == 'string' && data.queryStringObject.email.trim().length > 0 ? data.queryStringObject.email.trim() : false; 85 | if(email){ 86 | // Lookup the user 87 | _data.read('users',email,function(err,data){ 88 | if(!err && data){ 89 | // // Remove the hashed password from the user user object before returning it to the requester 90 | // delete data.hashedPassword; 91 | callback(200,data); 92 | } else { 93 | callback(404); 94 | } 95 | }); 96 | } else { 97 | _data.list("users", function(err,data){ 98 | if (!err && data) { 99 | callback (200,data) 100 | } else{ 101 | callback(400,{'Error' : 'can not desplay the available users'}); 102 | } 103 | }) 104 | } 105 | }; 106 | 107 | 108 | //Users-put 109 | //Required data : phone 110 | //Optional data: firstName, lastName, password (atleast one must be specified) 111 | //@TODO onlylet an authenticated user update their own, don't let him update others 112 | handlers._eit.put = function(data,callback){ 113 | var email = typeof(data.payload.email) == 'string' && data.payload.email.trim().length > 0 ? data.payload.email.trim() : false; 114 | //var phone = typeof(data.payload.phone) == 'string' && data.payload.phone.trim().length == 10 ? data.payload.phone.trim() : false; 115 | 116 | //check for the optional fields 117 | var firstName = typeof(data.payload.firstName) == 'string' && data.payload.firstName.trim().length > 0 ? data.payload.firstName.trim() : false; 118 | var lastName = typeof(data.payload.lastName) == 'string' && data.payload.lastName.trim().length > 0 ? data.payload.lastName.trim() : false; 119 | //var email = typeof(data.payload.email) == 'string' && data.payload.email.trim().length > 0 ? data.payload.email.trim() : false; 120 | var country = typeof(data.payload.country) == 'string' && data.payload.country.trim().length > 0 ? data.payload.country.trim() : false; 121 | var age = typeof(data.payload.age) == 'string' && data.payload.age.trim().length > 0 ? data.payload.age.trim() : false; 122 | 123 | //Error if the phone is invalid 124 | if (email){ 125 | //Error if nothing is sent to update 126 | if (firstName || lastName || country || age){ 127 | //lookup user 128 | _data.read('users',email,function(err,userData){ 129 | if(!err && userData){ 130 | //update the fields necessary 131 | if(firstName){ 132 | userData.firstName = firstName; 133 | } 134 | if(lastName){ 135 | userData.lastName = lastName; 136 | } 137 | if(country){ 138 | userData.country = country; 139 | } 140 | if(age){ 141 | userData.country = age; 142 | } 143 | //Store the new updates 144 | _data.update('users',email,userData,function(err){ 145 | if(!err){ 146 | callback(200); 147 | }else{ 148 | console.log(err); 149 | callback(500,{'Error' : 'Could not update the user'}); 150 | } 151 | }); 152 | } else{ 153 | callback(400,{'Error' : 'The specified user does not exist'}); 154 | } 155 | }); 156 | 157 | }else { 158 | Callback(400,{'Error' : 'Missing fields to update'}); 159 | } 160 | 161 | } else{ 162 | callback(400, {'Err':'Missing required field'}); 163 | } 164 | 165 | }; 166 | 167 | //Users-delete 168 | //Required field:phone 169 | //@TODO only let the authenticated user delete their object, don't let them delete anyone else's 170 | //@TODO clean up (delete) any other data files associated with this user 171 | handlers._eit.delete = function(data,callback){ 172 | // Check that phone number is valid 173 | var email = typeof(data.queryStringObject.email) == 'string' && data.queryStringObject.email.trim().length > 0 ? data.queryStringObject.email.trim() : false; 174 | if(email){ 175 | // Lookup the user 176 | _data.read('users',email,function(err,data){ 177 | if(!err && data){ 178 | _data.delete('users', email, function(err){ 179 | if(!err){ 180 | callback (200); 181 | } else{ 182 | callback(500, {'Error':'Could not find the specified user'}) 183 | } 184 | }) 185 | 186 | } else { 187 | callback(400,{'Err':'could not find the specified user'}); 188 | } 189 | }); 190 | } else { 191 | callback(400,{'Error' : 'Missing required field'}) 192 | } 193 | }; 194 | 195 | 196 | 197 | // Ping handler 198 | handlers.ping = function(data,callback){ 199 | callback(200); 200 | }; 201 | 202 | // Not-Found handler 203 | handlers.notFound = function(data,callback){ 204 | callback(404); 205 | }; 206 | 207 | //Export the module 208 | module.exports = handlers --------------------------------------------------------------------------------