// // Dependencies // let http = require('http'); let fs = require('fs'); // // Constants // let DATA_LOCATION = 'data'; // both the url root and the location of data file let DATA_LOCATION_LEN = DATA_LOCATION.length; let DATA_FILE = __dirname + '/' + DATA_LOCATION; let PORT = 1280; // // Load store file // let store = {}; // deafult empty object let json=''; try { let json = fs.readFileSync(DATA_FILE); store = JSON.parse(json); console.log('Read store file'); } catch (e) { // lazy error handling console.log('Could not load store file. Using empty array.'); } // // Flush to store file on exit // let flush = function() { console.log('Flushing data to file [' + DATA_FILE + ']\n'); fs.writeFileSync(DATA_FILE, JSON.stringify(store)); }; let handleInterrupt = function() { flush(); process.exit(); }; process.on('SIGINT', handleInterrupt); process.on('SIGTERM', handleInterrupt); process.on('SIGHUP', flush); // HUP flushes to file but keeps the server running // // If request URI is prefixed with the value of DATA_LOCATION, we treat incoming request as a REST request // Otherwise we serve the file referenced by the URI // let serveFile = function(loc, req, resp) { let fullPath = __dirname + '/' + loc; console.log('Trying to serve file at [' + fullPath + ']'); if (req.method !== 'GET') { // read only! resp.writeHead(405); resp.write('Unsupported method\n'); resp.end(); } else if (fs.existsSync(fullPath)) { resp.writeHead(200); fs.createReadStream(fullPath).pipe(resp); } else { resp.writeHead(404); resp.write('Not Found\n'); resp.end(); } }; let serveRestData = function(urlPath, req, resp) { console.log(req.method + ' request for path [' + urlPath + ']'); switch (req.method) { case 'GET': let exactMatch=!urlPath.endsWith('/'); let matchFound=false; if (exactMatch) { // assumes that only a single resource has this ID. console.log(" - Exact Match."); if (store.hasOwnProperty(urlPath)) { resp.writeHead(200, { 'Content-Type' : 'application/json' }); resp.write(JSON.stringify(store[urlPath]) + '\n'); matchFound=true; } } else { console.log(" - All Matches."); let matches=[]; Object.keys(store).forEach(theKey=>{ if (theKey.startsWith(urlPath)){ matches.push(store[theKey]); matchFound=true; } }); if (matchFound) { resp.writeHead(200, { 'Content-Type' : 'application/json' }); resp.write(JSON.stringify(matches)); } } if (!matchFound) { console.log(" - Match NOT found."); resp.writeHead(404, { 'Content-Type' : 'application/json' }); resp.write('{"success":false, "error":"Not Found"}'); } else { console.log(" - Match found."); } resp.end(); break; case 'PUT': json = ''; req.on('data', function(chunk) { json += chunk; }); req.on('end', function() { try { let data = JSON.parse(json); store[urlPath] = data; resp.writeHead(201, { 'Content-Type' : 'application/json' }); resp.write('{"success":true}'); } catch (e) { resp.writeHead(400, { 'Content-Type' : 'application/json' }); resp.write('{"success":false, "error":"Invalid JSON"}'); } resp.end(); flush(); }); break; case 'POST': json = ''; req.on('data', function(chunk) { json += chunk; }); req.on('end', function() { try { let data = JSON.parse(json); if (data.ID === undefined) { resp.writeHead(400, { 'Content-Type' : 'application/json' }); resp.write('{"success":false, "error":"The ID Field needs to be given"}'); } else { // make sure the ID from the data is used as the final resource Identifier, // even if the URL has none or says different. let re=new RegExp("/[^/]*$"); urlPath=urlPath.replace(re,""); urlPath=urlPath+"/"+data.ID; console.log(" - storing with resource key: [" + urlPath + "]"); store[urlPath] = data; resp.writeHead(201, { 'Content-Type' : 'application/json' }); resp.write(JSON.stringify(store[urlPath])); } } catch (e) { resp.writeHead(400, { 'Content-Type' : 'application/json' }); resp.write('{"success":false, "error":"Invalid JSON"}'); } resp.end(); flush(); }); break; case 'PATCH': json = ''; req.on('data', function(chunk) { json += chunk; }); req.on('end', function() { try { let data = JSON.parse(json); Object.keys(data).forEach(theKey=>{ store[urlPath][theKey] = data[theKey] }); resp.writeHead(201, { 'Content-Type' : 'application/json' }); resp.write('{"success":true}'); } catch (e) { resp.writeHead(400, { 'Content-Type' : 'application/json' }); resp.write('{"success":false, "error":"Invalid JSON"}'); } resp.end(); flush(); }); break; case 'OPTIONS': resp.end(); break; case 'DELETE': if (store.hasOwnProperty(urlPath)) { delete store[urlPath]; resp.writeHead(204, { 'Content-Type' : 'application/json' }); resp.write('{"success":true}'); } else { resp.writeHead(404, { 'Content-Type' : 'application/json' }); resp.write('{"success":false, "error":"Not Found"}'); } resp.end(); flush(); break; default: resp.writeHead(405, { 'Content-Type' : 'application/json' }); resp.write('{"success":false, "error":"Unsupported method"}'); resp.end(); } }; // // Listen for connections // http.createServer(function(req, resp) { // CORS headers resp.setHeader('Access-Control-Allow-Origin', '*'); resp.setHeader('Access-Control-Allow-Headers', 'X-Request-With, content-type'); resp.setHeader('Vary', 'Origin'); resp.setHeader('Access-Control-Allow-Methods','GET, PATCH, POST, PUT, DELETE, OPTIONS'); console.log('Serving [' + req.url + ']'); if (req.url === '/') { // server index file serveFile('index.html', req, resp); } else { // rest request serveRestData(req.url, req, resp); } }).listen(PORT);