From cb7527cebea27bf55c88ae25416178ced5e78383 Mon Sep 17 00:00:00 2001 From: lmachens Date: Tue, 23 Feb 2021 12:26:57 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20RESTful=20=20endpoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/api/tracks/[id].ts | 57 ++++++++++++++++++++++++++++++++++++--- pages/api/tracks/index.ts | 42 ++++++++++++++++++++++++++--- server/db.json | 7 +++++ server/db.ts | 19 +++++++++++++ server/samples.http | 32 ++++++++++++++++++++++ 5 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 server/db.ts create mode 100644 server/samples.http diff --git a/pages/api/tracks/[id].ts b/pages/api/tracks/[id].ts index 6001346..014da5b 100644 --- a/pages/api/tracks/[id].ts +++ b/pages/api/tracks/[id].ts @@ -1,9 +1,29 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction import { NextApiRequest, NextApiResponse } from "next"; -import db from "../../../server/db.json"; +import { readDb, writeDb } from "../../../server/db"; +import { APITrack } from "../../../utils/api"; -export default (req: NextApiRequest, res: NextApiResponse) => { +type Methods = { + [method: string]: (req: NextApiRequest, res: NextApiResponse) => void; +}; +const methods: Methods = { + GET: handleGet, + PATCH: handlePatch, + DELETE: handleDelete, +}; +export default async (req: NextApiRequest, res: NextApiResponse) => { + const method = methods[req.method]; + if (!method) { + return res.status(405).json({ + status: 405, + error: "Method not allowed", + }); + } + await method(req, res); +}; + +async function handleGet(req: NextApiRequest, res: NextApiResponse) { const { id } = req.query; + const db = await readDb(); const track = db.tracks.find((track) => track.id === id); if (!track) { return res.status(404).json({ @@ -12,4 +32,33 @@ export default (req: NextApiRequest, res: NextApiResponse) => { }); } res.status(200).json(track); -}; +} + +async function handlePatch(req: NextApiRequest, res: NextApiResponse) { + const { id } = req.query; + const partialTrack: APITrack = req.body; + + const db = await readDb(); + const track = db.tracks.find((track) => track.id === id); + if (!track) { + return res.status(404).json({ + status: 404, + error: "Track not found", + }); + } + Object.assign(track, partialTrack); + await writeDb(db); + res.status(200).json(track); +} + +async function handleDelete(req: NextApiRequest, res: NextApiResponse) { + const { id } = req.query; + + const db = await readDb(); + db.tracks = db.tracks.filter((track) => track.id !== id); + await writeDb(db); + res.status(202).json({ + status: 202, + message: "Track deleted", + }); +} diff --git a/pages/api/tracks/index.ts b/pages/api/tracks/index.ts index d8a7473..6eab7a3 100644 --- a/pages/api/tracks/index.ts +++ b/pages/api/tracks/index.ts @@ -1,7 +1,41 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction import { NextApiRequest, NextApiResponse } from "next"; -import db from "../../../server/db.json"; +import { readDb, writeDb } from "../../../server/db"; +import { APITrack } from "../../../utils/api"; -export default (_req: NextApiRequest, res: NextApiResponse) => { - res.status(200).json(db.tracks); +type Methods = { + [method: string]: (req: NextApiRequest, res: NextApiResponse) => void; +}; +const methods: Methods = { + GET: handleGet, + POST: handlePost, +}; +export default async (req: NextApiRequest, res: NextApiResponse) => { + const method = methods[req.method]; + if (!method) { + return res.status(405).json({ + status: 405, + error: "Method not allowed", + }); + } + await method(req, res); }; + +async function handleGet(req: NextApiRequest, res: NextApiResponse) { + const db = await readDb(); + res.status(200).json(db.tracks); +} + +async function handlePost(req: NextApiRequest, res: NextApiResponse) { + const newTrack: APITrack = req.body; + const db = await readDb(); + const trackExists = db.tracks.some((track) => track.id === newTrack.id); + if (trackExists) { + return res.status(409).json({ + status: 409, + error: "Track already exists", + }); + } + db.tracks.push(newTrack); + await writeDb(db); + res.status(201).json(newTrack); +} diff --git a/server/db.json b/server/db.json index cb37e5a..a30d997 100644 --- a/server/db.json +++ b/server/db.json @@ -13,6 +13,13 @@ "title": "The Unforgiven", "artist": "Metallica", "audioSrc": "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/KBOO/The_Underscore_Orkestra/No_Money_No_Honey_All_We_Got_Is_Us/The_Underscore_Orkestra_-_04_-_Magdalena.mp3" + }, + { + "id": "test", + "imgSrc": "https://images.unsplash.com/photo-1613473060226-dd81153a63db?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyfHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60", + "title": "Paul is Alive", + "artist": "Scooter", + "audioSrc": "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/KBOO/The_Underscore_Orkestra/No_Money_No_Honey_All_We_Got_Is_Us/The_Underscore_Orkestra_-_02_-_Blue_Draggish.mp3" } ] } diff --git a/server/db.ts b/server/db.ts new file mode 100644 index 0000000..8badaf2 --- /dev/null +++ b/server/db.ts @@ -0,0 +1,19 @@ +import fs from "fs/promises"; +import type { APITrack } from "../utils/api"; + +type DB = { + tracks: APITrack[]; +}; + +const DB_FILE = "./server/db.json"; // Relative to entry point + +export async function readDb() { + const dbJson = await fs.readFile(DB_FILE, "utf-8"); + const db: DB = JSON.parse(dbJson); + return db; +} + +export async function writeDb(newDb: DB) { + const dbJson = JSON.stringify(newDb, null, 2); + await fs.writeFile(DB_FILE, dbJson); +} diff --git a/server/samples.http b/server/samples.http new file mode 100644 index 0000000..2e5a574 --- /dev/null +++ b/server/samples.http @@ -0,0 +1,32 @@ +### GET all tracks +http://localhost:3000/api/tracks + +### GET a single track + +http://localhost:3000/api/tracks/scooter_paul-is-dead + +### POST a new track + +POST http://localhost:3000/api/tracks HTTP/1.1 +content-type: application/json + +{ + "id": "test", + "imgSrc": "https://images.unsplash.com/photo-1613473060226-dd81153a63db?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyfHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60", + "title": "Paul is Dead", + "artist": "Scooter", + "audioSrc": "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/KBOO/The_Underscore_Orkestra/No_Money_No_Honey_All_We_Got_Is_Us/The_Underscore_Orkestra_-_02_-_Blue_Draggish.mp3" +} + +### PATCH an existing track + +PATCH http://localhost:3000/api/tracks/test HTTP/1.1 +content-type: application/json + +{ + "title": "Paul is Alive" +} + +### DELETE a track + +DELETE http://localhost:3000/api/tracks/test HTTP/1.1 \ No newline at end of file