// // Dependencies // let http = require("http"); let fs = require("fs"); // // Constants // let DATA_LOCATION = "dataDir/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);