diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/routes.ts | 2 | ||||
| -rw-r--r-- | app/routes/api-artists.tsx | 47 | ||||
| -rw-r--r-- | app/routes/api-bands.tsx | 51 |
3 files changed, 100 insertions, 0 deletions
diff --git a/app/routes.ts b/app/routes.ts index a4e737f..d02abf7 100644 --- a/app/routes.ts +++ b/app/routes.ts @@ -2,6 +2,8 @@ import { type RouteConfig, index, route } from "@react-router/dev/routes"; export default [ index("routes/home.tsx"), + route("/api/bands", "routes/api-bands.tsx"), + route("/api/artists", "routes/api-artists.tsx"), route("/bands/new", "routes/band-new.tsx"), route("/bands/of/:uuid", "routes/band-by-uuid.tsx"), route("/bands/named/:slug", "routes/band-by-slug.tsx"), diff --git a/app/routes/api-artists.tsx b/app/routes/api-artists.tsx new file mode 100644 index 0000000..ed762bf --- /dev/null +++ b/app/routes/api-artists.tsx @@ -0,0 +1,47 @@ +import type { ActionFunctionArgs } from "react-router"; +import { createArtist, getIpAddress, listArtists, toSlug } from "~/lib/db.server"; + +export function loader() { + return Response.json(listArtists()); +} + +export async function action({ request }: ActionFunctionArgs) { + if (request.method !== "POST") { + return Response.json({ error: "Method not allowed" }, { status: 405 }); + } + + let body: Record<string, unknown>; + try { + body = await request.json(); + } catch { + return Response.json({ error: "Invalid JSON body" }, { status: 400 }); + } + + const name = (body.name as string | undefined)?.trim(); + if (!name) return Response.json({ error: "name is required" }, { status: 400 }); + + const slug = (body.slug as string | undefined)?.trim() || toSlug(name); + if (!slug) return Response.json({ error: "could not derive slug from name" }, { status: 400 }); + + const id = crypto.randomUUID(); + try { + const artist = createArtist({ + id, + slug, + name, + links: (body.links as { label: string; url: string }[]) || [], + message: (body.message as string) || "API import", + ip_address: getIpAddress(request), + }); + return Response.json(artist, { status: 201 }); + } catch (e) { + if (e instanceof Error && e.message.includes("UNIQUE constraint failed: artists.slug")) { + return Response.json({ error: "slug already in use" }, { status: 409 }); + } + throw e; + } +} + +export default function () { + return null; +} diff --git a/app/routes/api-bands.tsx b/app/routes/api-bands.tsx new file mode 100644 index 0000000..64a9269 --- /dev/null +++ b/app/routes/api-bands.tsx @@ -0,0 +1,51 @@ +import type { ActionFunctionArgs } from "react-router"; +import { createBand, getIpAddress, listBands, toSlug } from "~/lib/db.server"; + +export function loader() { + return Response.json(listBands()); +} + +export async function action({ request }: ActionFunctionArgs) { + if (request.method !== "POST") { + return Response.json({ error: "Method not allowed" }, { status: 405 }); + } + + let body: Record<string, unknown>; + try { + body = await request.json(); + } catch { + return Response.json({ error: "Invalid JSON body" }, { status: 400 }); + } + + const name = (body.name as string | undefined)?.trim(); + if (!name) return Response.json({ error: "name is required" }, { status: 400 }); + + const slug = (body.slug as string | undefined)?.trim() || toSlug(name); + if (!slug) return Response.json({ error: "could not derive slug from name" }, { status: 400 }); + + const id = crypto.randomUUID(); + try { + const band = createBand({ + id, + slug, + name, + area: (body.area as string) || null, + description: (body.description as string) || null, + status: (body.status as string) || "active", + links: (body.links as { label: string; url: string }[]) || [], + artists: (body.artists as { id: string; role: string | null }[]) || [], + message: (body.message as string) || "API import", + ip_address: getIpAddress(request), + }); + return Response.json(band, { status: 201 }); + } catch (e) { + if (e instanceof Error && e.message.includes("UNIQUE constraint failed: bands.slug")) { + return Response.json({ error: "slug already in use" }, { status: 409 }); + } + throw e; + } +} + +export default function () { + return null; +} |
