From 8cd028c434a01015eadf1c44ac1f398fb34f1015 Mon Sep 17 00:00:00 2001 From: intagold561 <263689503+intagold561@users.noreply.github.com> Date: Wed, 13 May 2026 16:46:21 +0800 Subject: [PATCH] feat: add GET /things/get and POST /things/delete endpoints with tests - Add GET /things/get endpoint to retrieve a single thing by thing_id - Add POST /things/delete endpoint to remove a thing by thing_id - Add removeThing method to database client - Add comprehensive tests for both new endpoints --- lib/db/db-client.ts | 5 +++++ routes/things/delete.ts | 16 +++++++++++++++ routes/things/get.ts | 25 +++++++++++++++++++++++ tests/routes/things/delete.test.ts | 32 ++++++++++++++++++++++++++++++ tests/routes/things/get.test.ts | 29 +++++++++++++++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 routes/things/delete.ts create mode 100644 routes/things/get.ts create mode 100644 tests/routes/things/delete.test.ts create mode 100644 tests/routes/things/get.test.ts diff --git a/lib/db/db-client.ts b/lib/db/db-client.ts index e525e65..148b3e1 100644 --- a/lib/db/db-client.ts +++ b/lib/db/db-client.ts @@ -21,4 +21,9 @@ const initializer = combine(databaseSchema.parse({}), (set) => ({ idCounter: state.idCounter + 1, })) }, + removeThing: (thing_id: string) => { + set((state) => ({ + things: state.things.filter((t) => t.thing_id !== thing_id), + })) + }, })) diff --git a/routes/things/delete.ts b/routes/things/delete.ts new file mode 100644 index 0000000..93c4722 --- /dev/null +++ b/routes/things/delete.ts @@ -0,0 +1,16 @@ +import { withRouteSpec } from "lib/middleware/with-winter-spec" +import { z } from "zod" + +export default withRouteSpec({ + methods: ["POST"], + jsonBody: z.object({ + thing_id: z.string(), + }), + jsonResponse: z.object({ + ok: z.boolean(), + }), +})(async (req, ctx) => { + const { thing_id } = await req.json() + ctx.db.removeThing(thing_id) + return ctx.json({ ok: true }) +}) diff --git a/routes/things/get.ts b/routes/things/get.ts new file mode 100644 index 0000000..d6c716b --- /dev/null +++ b/routes/things/get.ts @@ -0,0 +1,25 @@ +import { withRouteSpec } from "lib/middleware/with-winter-spec" +import { z } from "zod" + +export default withRouteSpec({ + methods: ["GET"], + queryParams: z.object({ + thing_id: z.string(), + }), + jsonResponse: z.object({ + thing: z.object({ + thing_id: z.string(), + name: z.string(), + description: z.string(), + }), + }), +})((req, ctx) => { + const { thing_id } = req.query + const thing = ctx.db.things.find((t) => t.thing_id === thing_id) + + if (!thing) { + return ctx.json({ error: "Thing not found" }, { status: 404 }) + } + + return ctx.json({ thing }) +}) diff --git a/tests/routes/things/delete.test.ts b/tests/routes/things/delete.test.ts new file mode 100644 index 0000000..1b496b0 --- /dev/null +++ b/tests/routes/things/delete.test.ts @@ -0,0 +1,32 @@ +import { getTestServer } from "tests/fixtures/get-test-server" +import { test, expect } from "bun:test" + +test("delete a thing", async () => { + const { axios } = await getTestServer() + + await axios.post("/things/create", { + name: "Thing1", + description: "Thing1 Description", + }) + + const { data: listBefore } = await axios.get("/things/list") + expect(listBefore.things).toHaveLength(1) + + await axios.post("/things/delete", { + thing_id: "0", + }) + + const { data: listAfter } = await axios.get("/things/list") + expect(listAfter.things).toHaveLength(0) +}) + +test("delete a non-existent thing does not error", async () => { + const { axios } = await getTestServer() + + const res = await axios.post("/things/delete", { + thing_id: "999", + }) + + expect(res.status).toBe(200) + expect(res.data.ok).toBe(true) +}) diff --git a/tests/routes/things/get.test.ts b/tests/routes/things/get.test.ts new file mode 100644 index 0000000..2c373ef --- /dev/null +++ b/tests/routes/things/get.test.ts @@ -0,0 +1,29 @@ +import { getTestServer } from "tests/fixtures/get-test-server" +import { test, expect } from "bun:test" + +test("get a thing by id", async () => { + const { axios } = await getTestServer() + + await axios.post("/things/create", { + name: "Thing1", + description: "Thing1 Description", + }) + + const { data } = await axios.get("/things/get?thing_id=0") + + expect(data.thing).toEqual({ + thing_id: "0", + name: "Thing1", + description: "Thing1 Description", + }) +}) + +test("get a thing that doesn't exist returns 404", async () => { + const { axios } = await getTestServer() + + try { + await axios.get("/things/get?thing_id=999") + } catch (e: any) { + expect(e.status).toBe(404) + } +})