routes/index.js: used for defined all the endpoints:
import express from "express"; import * as notes from "./notes.js"; const router = express.Router(); router.get("/notes", notes.list); router.post("/notes", notes.create); // curl -X POST http://localhost:3000/notes router.get("/notes/:id", notes.read); router.post("/notes/:id", notes.update); // curl -X POST http://localhost:3000/notes/123 router.delete("/notes/:id", notes.deleteNote); // curl -X DELETE http://localhost:3000/notes export default router;
routes/notes.js: used for defined collections for CRUD:
import * as Note from "../model/Note.js"; // curl "http://localhost:3000/notes?sort=DESC" export function list(req, res) { let { sort } = req.query; sort = sort ? sort.toLowerCase() : "desc"; if (sort !== "asc" && sort !== "desc") { return res.status(400).send("invalid sort params"); } const notes = Note.getNotes(sort); res.json({ notes }); } // curl -X POST -d title="hello" -d body="world" http://localhost:3000/notes/ export async function create(req, res) { const { title, body } = req.body; if (title == undefined || body == undefined) { return res.status(400).send("Invalid request"); } const note = Note.createNote({ title, body }); res.status(201).send({ message: "ok", data: note, }); } export async function read(req, res) { const { id } = body.params; if (id == undefined) { return res.status(400).send("Invalid request"); } const note = await Note.getNode(id); res.json(note); } // curl -X POST -d title="hello" -d body="world" http://localhost:3000/notes/123 export async function update(req, res) { const { id } = req.params; const { title, body } = req.body; if (title == undefined && body == undefined) { return res.status(400).send("Invalid request"); } const note = Note.updateNote(id, { title, body }); res.send({ message: "ok", data: note }); } // curl -X DELETE http://localhost:3000/notes/123 export async function deleteNote(req, res) { const { id } = req.params; await Note.deleteNode(id); res.send("ok"); }
model/Note.js: Do CRUD:
import { v4 as uuid } from "uuid"; import MapStore from "../lib/mapstore.js"; const NOTES = new Map(); const store = new MapStore("notes.json"); /* Note { id: String title: String body: String lastEdited: Date }*/ store .read() .then((notes) => { for (let [id, note] of notes) { NOTES.set(id, note); } }) .catch((err) => { console.error(err); }); export function getNotes(sort) { const notes = Array.from(NOTES.values()); if (sort === "asc") { return notes.sort((a, b) => { return a.lastEdited - b.lastEdited; }); } else { return notes.sort((a, b) => { return b.lastEdited - a.lastEdited; }); } return; } export async function createNote({ title, body }) { const id = uuid(); const lastEdited = Date.now(); const note = { id, title, body, lastEdited, }; NOTES.set(id, note); await store.save(NOTES); return { ...note }; } export async function updateNote(id, { title, body }) { if (!NOTES.has(id)) { return null; } const note = NOTES.get(id); note.title = title ?? note.title; note.body = body ?? note.body; note.lastEdited = Date.now(); await store.save(NOTES); return { ...note }; } export function getNode(id) { if (!NOTES.has(id)) { return null; } const note = NOTES.get(id); return { ...note }; } export async function deleteNode(id) { const successed = NOTES.delete(id); await store.save(NOTES); return successed; }
lib/mapstore.js: runtime memory:
import { readFile, writeFile } from "fs/promises"; import path from "path"; const dataDir = "data"; class MapStore { constructor(filename) { this.filepath = path.resolve(dataDir, filename); } async save(data) { console.log(`writing to ${this.filepath}`); const serializedData = JSON.stringify(Array.from(data.entries())); await writeFile(this.filepath, serializedData); } async read() { console.log(`readubg frin ${this.filepath}`); const data = await readFile(this.filepath, "utf-8"); const parsed = JSON.parse(data); return new Map(parsed); } } export default MapStore;
index.js:
import express from "express"; // Logging import morgan from "morgan"; import routes from "./routes/index.js"; const app = express(); app.use( morgan(":method :url :status :res[content-length] - :response-time ms") ); // encode post body and available on req.body app.use(express.urlencoded({ extended: true })); // Routers app.use(routes); // Trigger a error for testing app.get("/error", function (req, res) { throw new Error("oops I made a mistake"); }); // Error handler middleware app.use(function (err, req, res, next) { console.error(err.stack); res.status(500).send(err.message); }); // 404 catch app.use(function (req, res) { res.status(404).send("not found"); }); app.listen(3000, function () { console.log("app is listening on port 3000"); });