diff --git a/src/handlers/deleteIdea.ts b/src/handlers/deleteIdea.ts new file mode 100644 index 0000000..ce614c8 --- /dev/null +++ b/src/handlers/deleteIdea.ts @@ -0,0 +1,10 @@ +import { eq } from "drizzle-orm"; +import db from "../db"; +import { ideasTable } from "../db/schema"; +import { Request, Response } from "express"; + +export default async function deleteIdeaHandler(req: Request, res: Response) { + const { id } = req.params; + await db.delete(ideasTable).where(eq(ideasTable.id, Number(id))); + res.json({message: "Idea deleted"}) +} \ No newline at end of file diff --git a/src/handlers/getIdea.ts b/src/handlers/getIdea.ts new file mode 100644 index 0000000..813bca9 --- /dev/null +++ b/src/handlers/getIdea.ts @@ -0,0 +1,10 @@ +import db from "../db"; +import { ideasTable } from "../db/schema"; +import { Request, Response } from "express"; +import { eq } from "drizzle-orm"; + +export default async function getIdeaHandler(req: Request, res: Response) { + const { id } = req.params; + const idea = await db.select().from(ideasTable).where(eq(ideasTable.id, Number(id))); + res.json(idea); +} \ No newline at end of file diff --git a/src/handlers/newIdea.ts b/src/handlers/newIdea.ts index e6196fe..9752275 100644 --- a/src/handlers/newIdea.ts +++ b/src/handlers/newIdea.ts @@ -6,10 +6,10 @@ import { ideasTable } from "../db/schema"; export default async function newIdeaHandler(req: TypedRequest>, res: Response) { const {name, description, notes} = req.body; - await db.insert(ideasTable).values({ + const [{id}] = await db.insert(ideasTable).values({ name: name || "", description: description || "", notes: notes || "" - }) - res.status(201).json({message: "Idea created"}) + }).returning({id: ideasTable.id }) + res.status(201).json({message: "Idea created", id}); } \ No newline at end of file diff --git a/src/handlers/updateIdea.ts b/src/handlers/updateIdea.ts new file mode 100644 index 0000000..4680610 --- /dev/null +++ b/src/handlers/updateIdea.ts @@ -0,0 +1,24 @@ +import { Response } from "express"; +import db from "../db"; +import { ideasTable } from "../db/schema"; +import { eq, sql } from "drizzle-orm"; +import { TypedRequest, updateIdeaSchema } from "../schemas"; +import z from "zod"; + +export default async function updateIdeaHandler(req: TypedRequest>, res: Response) { + let {id} = req.params; + const idParseResult = z.number().int().safeParse(Number(id)); + if (!idParseResult.success) { + res.status(400).json({message: "Invalid idea ID"}); + return; + } + id = idParseResult.data; + const {name, description, notes} = req.body; + await db.update(ideasTable).set({ + ...(name !== undefined ? { name } : {}), + ...(description !== undefined ? { description } : {}), + ...(notes !== undefined ? { notes } : {}), + updatedAt: sql`(unixepoch())` + }).where(eq(ideasTable.id, Number(id))) + res.json({message: "Idea updated", id}); +} diff --git a/src/index.ts b/src/index.ts index 1542104..273faa6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,11 @@ import express from "express" -import { newIdeaSchema, validateSchema } from "./schemas"; +import { newIdeaSchema, updateIdeaSchema, validateSchema } from "./schemas"; import newIdeaHandler from "./handlers/newIdea"; import getIdeasHandler from "./handlers/getIdeas"; +import getIdeaHandler from "./handlers/getIdea"; import previewIdeasHandler from "./handlers/previewIdeas"; +import deleteIdeaHandler from "./handlers/deleteIdea"; +import updateIdeaHandler from "./handlers/updateIdea"; const spark = express(); spark.use(express.json()); @@ -10,6 +13,10 @@ spark.use(express.json()); spark.post("/idea", validateSchema(newIdeaSchema), newIdeaHandler); spark.get("/idea", getIdeasHandler); spark.get("/idea/preview", previewIdeasHandler); +spark.get("/idea/:id", getIdeaHandler); +spark.patch("/idea/:id", validateSchema(updateIdeaSchema), updateIdeaHandler); +spark.delete("/idea/:id", deleteIdeaHandler); + const PORT: number = Number(process.env.SPARK_PORT || 7654); spark.listen(PORT, () => { diff --git a/src/schemas.ts b/src/schemas.ts index 2b342a3..4d8e909 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -3,9 +3,11 @@ import z from "zod"; //#region Credit to Galtzabari export interface TypedRequest extends Express.Request { + // allow any params shape to be compatible with Express's ParamsDictionary + params: Record; body: T; } -export const validateSchema = (schema: T): RequestHandler => { +export const validateSchema = (schema: T, idRequired: boolean = false): RequestHandler => { return ( req: TypedRequest>, res: Response, @@ -20,6 +22,16 @@ export const validateSchema = (schema: T): RequestHandle }); return; } + if (idRequired) { + const idValidationResult = z.number().int().safeParse(req.params.id); + if (!idValidationResult.success) { + res.status(400).json({ + message: "Invalid ID parameter", + errors: idValidationResult.error.issues, + }); + return; + } + } // Overwrite the req.body with validated data req.body = validationResult.data; @@ -34,3 +46,10 @@ export const newIdeaSchema = z.object({ description: z.string().optional(), notes: z.string().optional() }) + +export const updateIdeaSchema = z.object({ + id: z.number().int(), + name: z.string().optional(), + description: z.string().optional(), + notes: z.string().optional() +})