publishing2

This commit is contained in:
Nicholas Keller
2026-07-28 10:57:02 -04:00
parent a47eb13b62
commit 85e2eaf1ca
6 changed files with 75 additions and 5 deletions
+10
View File
@@ -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"})
}
+10
View File
@@ -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);
}
+3 -3
View File
@@ -6,10 +6,10 @@ import { ideasTable } from "../db/schema";
export default async function newIdeaHandler(req: TypedRequest<z.output<typeof newIdeaSchema>>, res: Response) { export default async function newIdeaHandler(req: TypedRequest<z.output<typeof newIdeaSchema>>, res: Response) {
const {name, description, notes} = req.body; const {name, description, notes} = req.body;
await db.insert(ideasTable).values({ const [{id}] = await db.insert(ideasTable).values({
name: name || "", name: name || "",
description: description || "", description: description || "",
notes: notes || "" notes: notes || ""
}) }).returning({id: ideasTable.id })
res.status(201).json({message: "Idea created"}) res.status(201).json({message: "Idea created", id});
} }
+24
View File
@@ -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<z.output<typeof updateIdeaSchema>>, 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});
}
+8 -1
View File
@@ -1,8 +1,11 @@
import express from "express" import express from "express"
import { newIdeaSchema, validateSchema } from "./schemas"; import { newIdeaSchema, updateIdeaSchema, validateSchema } from "./schemas";
import newIdeaHandler from "./handlers/newIdea"; import newIdeaHandler from "./handlers/newIdea";
import getIdeasHandler from "./handlers/getIdeas"; import getIdeasHandler from "./handlers/getIdeas";
import getIdeaHandler from "./handlers/getIdea";
import previewIdeasHandler from "./handlers/previewIdeas"; import previewIdeasHandler from "./handlers/previewIdeas";
import deleteIdeaHandler from "./handlers/deleteIdea";
import updateIdeaHandler from "./handlers/updateIdea";
const spark = express(); const spark = express();
spark.use(express.json()); spark.use(express.json());
@@ -10,6 +13,10 @@ spark.use(express.json());
spark.post("/idea", validateSchema(newIdeaSchema), newIdeaHandler); spark.post("/idea", validateSchema(newIdeaSchema), newIdeaHandler);
spark.get("/idea", getIdeasHandler); spark.get("/idea", getIdeasHandler);
spark.get("/idea/preview", previewIdeasHandler); 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); const PORT: number = Number(process.env.SPARK_PORT || 7654);
spark.listen(PORT, () => { spark.listen(PORT, () => {
+20 -1
View File
@@ -3,9 +3,11 @@ import z from "zod";
//#region Credit to Galtzabari //#region Credit to Galtzabari
export interface TypedRequest<T> extends Express.Request { export interface TypedRequest<T> extends Express.Request {
// allow any params shape to be compatible with Express's ParamsDictionary
params: Record<string, any>;
body: T; body: T;
} }
export const validateSchema = <T extends z.ZodTypeAny>(schema: T): RequestHandler => { export const validateSchema = <T extends z.ZodTypeAny>(schema: T, idRequired: boolean = false): RequestHandler => {
return ( return (
req: TypedRequest<z.output<T>>, req: TypedRequest<z.output<T>>,
res: Response, res: Response,
@@ -20,6 +22,16 @@ export const validateSchema = <T extends z.ZodTypeAny>(schema: T): RequestHandle
}); });
return; 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 // Overwrite the req.body with validated data
req.body = validationResult.data; req.body = validationResult.data;
@@ -34,3 +46,10 @@ export const newIdeaSchema = z.object({
description: z.string().optional(), description: z.string().optional(),
notes: 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()
})