From 10ec05b94d9dc48968fcdc2c4352f25cba4dfbb7 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 15 Jan 2026 14:19:52 -0500 Subject: [PATCH 1/2] fix: use safeParseJson for POST /api/artists body parsing Use shared safeParseJson utility which returns {} for empty/invalid JSON instead of throwing an error. This allows the docs UI to work when no body is provided - the schema validation will catch missing required fields. Co-Authored-By: Claude Opus 4.5 --- .../__tests__/createArtistPostHandler.test.ts | 5 ++-- .../validateCreateArtistBody.test.ts | 5 ++-- lib/artists/validateCreateArtistBody.ts | 26 ++++--------------- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/lib/artists/__tests__/createArtistPostHandler.test.ts b/lib/artists/__tests__/createArtistPostHandler.test.ts index c764c5da..78ee84a4 100644 --- a/lib/artists/__tests__/createArtistPostHandler.test.ts +++ b/lib/artists/__tests__/createArtistPostHandler.test.ts @@ -168,7 +168,7 @@ describe("createArtistPostHandler", () => { expect(response.status).toBe(400); }); - it("returns 400 for invalid JSON body", async () => { + it("returns 400 for invalid JSON body (treated as empty)", async () => { const request = new NextRequest("http://localhost/api/artists", { method: "POST", headers: { @@ -181,8 +181,9 @@ describe("createArtistPostHandler", () => { const response = await createArtistPostHandler(request); const data = await response.json(); + // safeParseJson returns {} for invalid JSON, so schema validation catches it expect(response.status).toBe(400); - expect(data.error).toBe("Invalid JSON body"); + expect(data.error).toBe("name is required"); }); it("returns 500 when artist creation fails", async () => { diff --git a/lib/artists/__tests__/validateCreateArtistBody.test.ts b/lib/artists/__tests__/validateCreateArtistBody.test.ts index d5e00453..cc619b08 100644 --- a/lib/artists/__tests__/validateCreateArtistBody.test.ts +++ b/lib/artists/__tests__/validateCreateArtistBody.test.ts @@ -132,7 +132,7 @@ describe("validateCreateArtistBody", () => { } }); - it("returns 400 for invalid JSON body", async () => { + it("returns schema error for invalid JSON body (treated as empty)", async () => { const request = new NextRequest("http://localhost/api/artists", { method: "POST", headers: { @@ -144,11 +144,12 @@ describe("validateCreateArtistBody", () => { const result = await validateCreateArtistBody(request); + // safeParseJson returns {} for invalid JSON, so schema validation catches it expect(result).toBeInstanceOf(NextResponse); if (result instanceof NextResponse) { expect(result.status).toBe(400); const data = await result.json(); - expect(data.error).toBe("Invalid JSON body"); + expect(data.error).toBe("name is required"); } }); diff --git a/lib/artists/validateCreateArtistBody.ts b/lib/artists/validateCreateArtistBody.ts index edfab638..6804b276 100644 --- a/lib/artists/validateCreateArtistBody.ts +++ b/lib/artists/validateCreateArtistBody.ts @@ -2,20 +2,13 @@ import { NextRequest, NextResponse } from "next/server"; import { getCorsHeaders } from "@/lib/networking/getCorsHeaders"; import { getApiKeyDetails } from "@/lib/keys/getApiKeyDetails"; import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; +import { safeParseJson } from "@/lib/networking/safeParseJson"; import { z } from "zod"; export const createArtistBodySchema = z.object({ - name: z - .string({ message: "name is required" }) - .min(1, "name cannot be empty"), - account_id: z - .string() - .uuid("account_id must be a valid UUID") - .optional(), - organization_id: z - .string() - .uuid("organization_id must be a valid UUID") - .optional(), + name: z.string({ message: "name is required" }).min(1, "name cannot be empty"), + account_id: z.string().uuid("account_id must be a valid UUID").optional(), + organization_id: z.string().uuid("organization_id must be a valid UUID").optional(), }); export type CreateArtistBody = z.infer; @@ -52,16 +45,7 @@ export async function validateCreateArtistBody( ); } - let body: unknown; - try { - body = await request.json(); - } catch { - return NextResponse.json( - { status: "error", error: "Invalid JSON body" }, - { status: 400, headers: getCorsHeaders() }, - ); - } - + const body = await safeParseJson(request); const result = createArtistBodySchema.safeParse(body); if (!result.success) { const firstError = result.error.issues[0]; From 5dc6d852420ac8499591c62aac22adecd00e5734 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 15 Jan 2026 14:21:55 -0500 Subject: [PATCH 2/2] fix: use z.uuid() instead of deprecated z.string().uuid() Zod 4.x deprecates z.string().uuid() in favor of z.uuid() directly. Co-Authored-By: Claude Opus 4.5 --- lib/artists/validateCreateArtistBody.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/artists/validateCreateArtistBody.ts b/lib/artists/validateCreateArtistBody.ts index 6804b276..6b4e0b83 100644 --- a/lib/artists/validateCreateArtistBody.ts +++ b/lib/artists/validateCreateArtistBody.ts @@ -7,8 +7,8 @@ import { z } from "zod"; export const createArtistBodySchema = z.object({ name: z.string({ message: "name is required" }).min(1, "name cannot be empty"), - account_id: z.string().uuid("account_id must be a valid UUID").optional(), - organization_id: z.string().uuid("organization_id must be a valid UUID").optional(), + account_id: z.uuid({ message: "account_id must be a valid UUID" }).optional(), + organization_id: z.uuid({ message: "organization_id must be a valid UUID" }).optional(), }); export type CreateArtistBody = z.infer;