Last active
July 7, 2023 02:44
-
-
Save clavery/54c2d664ec3b504959ebd1b13f741129 to your computer and use it in GitHub Desktop.
Simple HTTP Rest Server in Node that operates on a JSON file backend
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Simple API Sample Server | |
* | |
* Serves from file ./_data.json writing to arrays with GET, POST, PUT, PATCH, DELETE | |
* | |
* Create a _data.json file like: | |
* | |
* { | |
* "todos": [], | |
* "people": [] | |
* } | |
* | |
* Then use Rest actions against /todos/{id}, /people/{id} | |
*/ | |
const http = require('node:http'); | |
const fs = require('node:fs'); | |
const crypto = require("node:crypto"); | |
const DATA_FILE = process.env.DATA_FILE ?? "./_data.json" | |
/** | |
* create UUID for IDs | |
* @returns {string} UUID | |
*/ | |
function uuid4() { | |
var rnd = crypto.randomBytes(16); | |
rnd[6] = (rnd[6] & 0x0f) | 0x40; | |
rnd[8] = (rnd[8] & 0x3f) | 0x80; | |
rnd = rnd.toString('hex').match(/(.{8})(.{4})(.{4})(.{4})(.{12})/); | |
rnd.shift(); | |
return rnd.join('-'); | |
} | |
const server = http.createServer( | |
/** | |
* @param {http.ClientRequest} req | |
* @param {http.ServerResponse} res | |
*/ | |
(req, res) => { | |
console.info(`[REQ] ${req.method} ${req.url}`) | |
res.setHeader("Access-Control-Allow-Origin", "*") | |
var body = [] | |
req.on('data', (chunk) => { | |
body.push(chunk) | |
}).on('end', () => { | |
body = Buffer.concat(body).toString() | |
var resp = {} | |
const contentType = "application/json" | |
res.setHeader("content-type", contentType) | |
var data; | |
try { | |
data = JSON.parse(fs.readFileSync(DATA_FILE).toString()) | |
} catch (e) { | |
console.error(`[RES] 500 ${e.message}`) | |
res.statusCode = 500 | |
res.write(JSON.stringify({"error": e.message}, null, 2)) | |
res.end(); | |
return | |
} | |
if (req.method === 'OPTIONS') { | |
res.setHeader("Access-Control-Allow-Methods", "POST, PUT, PATCH, GET, OPTIONS, DELETE") | |
res.setHeader("Access-Control-Allow-Headers", "*") | |
res.statusCode = 200 | |
res.end() | |
return | |
} | |
try { | |
if (req.url.length === 1) { | |
resp = data | |
} else { | |
var parts = req.url.split('/') | |
var type = parts[1] | |
let id = parts[2] | |
if (!data[type]) { | |
res.statusCode = 404 | |
resp = {"error": "Not Found"} | |
} else if (req.method === "GET") { | |
if (id) { | |
resp = data[type].find(i => i.id === id) | |
if (!resp) { | |
res.statusCode = 404 | |
resp = {"error": "Not Found"} | |
} | |
} else { | |
resp = data[type] | |
} | |
} else if (req.method === "POST") { | |
if (id) { | |
res.statusCode = 405 | |
resp = {"error": "Method not Allowed"} | |
} else { | |
id = uuid4() | |
resp = { | |
id: id, | |
...JSON.parse(body) | |
} | |
data[type].push(resp) | |
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2)) | |
} | |
// TODO: put shouldn't act exactly like patch | |
} else if (req.method === "PUT" || req.method === "PATCH") { | |
let obj = data[type].find(i => i.id === id) | |
if (!obj) { | |
res.statusCode = 404 | |
resp = {"error": "Not Found"} | |
} else { | |
resp = Object.assign(obj, JSON.parse(body), {id}) | |
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2)) | |
} | |
} else if (req.method === "DELETE") { | |
let idx = data[type].findIndex(i => i.id === id) | |
if (idx === -1) { | |
res.statusCode = 404 | |
resp = {"error": "Not Found"} | |
} else { | |
res.statusCode = 204 | |
data[type].splice(idx, 1) | |
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2)) | |
} | |
} else { | |
throw new Error('unsupported') | |
} | |
} | |
} catch (e) { | |
res.statusCode = 400 | |
resp = {"error": e.message} | |
} | |
const _resp = JSON.stringify(resp, null, 2) | |
console.info(`[RES] ${res.statusCode} ${contentType}\n${_resp}`) | |
res.write(_resp) | |
res.end() | |
}) | |
}); | |
server.on('clientError', (err, socket) => { | |
console.error(`[RES] 400 ${err.message}`) | |
}); | |
server.listen(8000, () => { | |
console.info("Listening on 8000...") | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment