Skip to content

Instantly share code, notes, and snippets.

@mikaelbr
Created November 20, 2019 07:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikaelbr/ccb1153935f44c1d0f62dc7c77d616c4 to your computer and use it in GitHub Desktop.
Save mikaelbr/ccb1153935f44c1d0f62dc7c77d616c4 to your computer and use it in GitHub Desktop.
import http from "http";
const db = createDb();
const app = createApp();
const router = app()
.on("GET", "/api/score", function(req, res) {
result(res, 200, { scores: db.entries() });
})
.on("POST", "/api/score", function(req, res) {
const { name, score } = req.body;
if (!name || !score) {
return result(res, 400, { message: "Bad request" });
}
result(res, 200, db.insert(name, score));
})
.on("GET", /\/api\/score\/(?<id>\w+)/, function(req, res) {
const score = db.get(req.params.id);
if (!score) {
return result(res, 404, { message: "Not found" });
}
result(res, 200, score);
})
.on("DELETE", /\/api\/score\/(?<id>\w+)/, function(req, res) {
const score = db.delete(req.params.id);
if (!score) {
return result(res, 400, { message: "Bad Request" });
}
result(res, 200, { message: "ok" });
})
.on("PUT", /\/api\/score\/(?<id>\w+)/, function(req, res) {
const { name, score } = req.body;
if (!name || !score) {
return result(res, 400, { message: "Bad request" });
}
const scoreItem = db.update(req.params.id, name, score);
if (!scoreItem) {
return result(res, 404, { message: "Not found" });
}
result(res, 200, scoreItem);
})
.fallback(function(_, res) {
result(res, 404, { message: "Not found" });
});
const server = http.createServer(router.handle);
const port = process.env.PORT || 3001;
server.listen(port, function() {
console.log(`Now listening to http://localhost:${port}`);
});
// Library implementation
// Own module, just as function here.
function createApp() {
return function app(routes = []) {
return {
on(method, path, cb) {
return app(
routes.concat({
method,
path,
cb
})
);
},
fallback(cb) {
return app(
routes.concat({
fallback: true,
method: "-",
path: "-",
cb
})
);
},
async handle(req, res) {
for (let { method, path, cb } of routes) {
if (
!isMethodMatch(req.method, method) ||
!isRouteMatch(req.url, path)
) {
continue;
}
req.body = await bufferData(req);
req.params = getParams(req.url, path);
return cb(req, res);
}
const noHit = routes.find(i => i.fallback);
if (noHit) {
return noHit.cb(req, res);
}
result(res, 400, { message: "Bad request" });
}
};
};
function isMethodMatch(sMethod, pMethod) {
return sMethod.toLowerCase() === pMethod.toLowerCase() || pMethod === "*";
}
function isRouteMatch(path, pattern) {
if (typeof pattern === "string") {
return path.toLowerCase() === pattern.toLowerCase();
}
if (pattern instanceof RegExp) {
return pattern.exec(path) !== null;
}
return false;
}
function getParams(path, pattern) {
if (pattern instanceof RegExp) {
const match = pattern.exec(path);
return match.groups || {};
}
return {};
}
async function bufferData(req) {
return new Promise(function(res, rej) {
let data = [];
req.on("data", chunk => {
data.push(chunk);
});
req.on("end", () => {
if (!data.length) {
res({});
} else {
res(JSON.parse(data));
}
});
});
}
}
function result(res, status, body) {
const data = JSON.stringify(body);
return res
.writeHead(status, {
"Content-Length": Buffer.byteLength(data),
"Content-Type": "application/json"
})
.end(data);
}
// Own module also, but yeah.
function createDb() {
let scoresData = {
0: {
id: 0,
name: "foo@dsa.com",
score: 3000,
timestamp: new Date()
},
1: {
id: 1,
name: "bar@dsa.com",
score: 2000,
timestamp: new Date()
}
};
function rand() {
return Math.random()
.toString(36)
.replace(/[^a-z]+/g, "")
.substr(2, 10);
}
return {
entries() {
return Object.values(scoresData);
},
get(id) {
return scoresData[id];
},
insert(name, score) {
const id = rand();
const newObj = {
name,
score,
id
};
scoresData[id] = newObj;
return newObj;
},
delete(id) {
const score = scoresData[id];
if (!score) return false;
delete scoresData[id];
return true;
},
update(id, name, score) {
const scoreItem = scoresData[id];
if (!scoreItem) return false;
const newObj = {
...scoreItem,
name,
score
};
scoresData[id] = newObj;
return newObj;
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment