Skip to content

Return 400 for malformed bulk status JSON#461

Merged
ralyodio merged 1 commit into
profullstack:masterfrom
rissrice2105-agent:codex/applications-bulk-status-json-400
Jun 14, 2026
Merged

Return 400 for malformed bulk status JSON#461
ralyodio merged 1 commit into
profullstack:masterfrom
rissrice2105-agent:codex/applications-bulk-status-json-400

Conversation

@rissrice2105-agent

Copy link
Copy Markdown
Contributor

Closes #460.

Summary

  • Parse PUT /api/applications/bulk-status bodies with a small guarded JSON helper.
  • Return 400 Invalid JSON body for malformed request JSON instead of the generic 500.
  • Add regression coverage that malformed JSON returns before any Supabase query.

Verification

  • corepack pnpm vitest run src/app/api/applications/bulk-status/route.test.ts
  • corepack pnpm tsc --noEmit

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes the PUT /api/applications/bulk-status route returning a generic 500 when the request body is not valid JSON, replacing it with a clean 400 response. A small parseJsonBody helper wraps request.json() in a try/catch and returns a pre-built NextResponse on failure, which the handler returns early before touching Supabase.

  • route.ts: Adds parseJsonBody that catches JSON parse errors and short-circuits with 400 Invalid JSON body; the existing Zod validation and Supabase logic are otherwise unchanged.
  • route.test.ts: New regression test verifying that a malformed body ("{") yields a 400 response and that supabase.from is never invoked.

Confidence Score: 4/5

Safe to merge — the change is narrow and well-tested; the only callouts are stylistic.

The implementation is correct and the regression test exercises exactly the broken path. The two comments are both non-blocking style points: the implicit union guard in the route and the incomplete Supabase mock stub in the test file that would only matter if more test cases are added later.

No files require special attention; both changed files are small and self-contained.

Important Files Changed

Filename Overview
src/app/api/applications/bulk-status/route.ts Adds parseJsonBody helper to catch malformed JSON and return 400 before reaching Supabase; logic is correct and minimal.
src/app/api/applications/bulk-status/route.test.ts New test file with a single regression case verifying malformed JSON → 400 and no Supabase calls; mocks are wired correctly but supabase chain mock is incomplete for any future non-400 test cases.

Sequence Diagram

sequenceDiagram
    participant Client
    participant PUT as PUT /api/applications/bulk-status
    participant Auth as getAuthContext
    participant Parse as parseJsonBody
    participant Supabase

    Client->>PUT: PUT request (body)
    PUT->>Auth: getAuthContext(request)
    Auth-->>PUT: "null | { user, supabase }"
    alt auth is null
        PUT-->>Client: 401 Unauthorized
    else auth ok
        PUT->>Parse: parseJsonBody(request)
        alt malformed JSON
            Parse-->>PUT: "{ response: 400 Invalid JSON body }"
            PUT-->>Client: 400 Invalid JSON body
        else valid JSON
            Parse-->>PUT: "{ body: parsed }"
            PUT->>PUT: bulkStatusSchema.safeParse(body)
            alt schema invalid
                PUT-->>Client: 400 Validation error
            else schema valid
                PUT->>Supabase: SELECT applications WHERE id IN (...)
                Supabase-->>PUT: applications[]
                PUT->>Supabase: "UPDATE applications SET status=..."
                Supabase-->>PUT: updatedApplications[]
                PUT->>Supabase: INSERT notifications
                PUT-->>Client: "200 { updated, applications }"
            end
        end
    end
Loading

Reviews (1): Last reviewed commit: "Handle malformed bulk status JSON" | Re-trigger Greptile

Comment on lines +36 to +38
if (parsed.response) return parsed.response;

const body = parsed.body;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Implicit discriminated-union access may obscure intent

parsed.response works at runtime because { body: any } never carries a response key, but TypeScript resolves this through an inferred union rather than an explicit discriminant — meaning future changes to parseJsonBody could silently break narrowing without a type error. Using 'response' in parsed as the guard makes the discriminant explicit and is also the idiomatic TypeScript way to narrow this union.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

}));

const mockFrom = vi.fn();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 mockFrom is declared but never given a return value

mockFrom is asserted to not be called in the malformed-JSON test, which is correct. However, vi.fn() returns undefined by default, so any future test case in this file that exercises the happy path will get an immediate crash when the route calls supabase.from(...).select(...). Consider adding a minimal chain stub (e.g., .mockReturnValue({ select: vi.fn(), in: vi.fn(), ... })) in beforeEach so the fixture is ready for follow-on tests.

@rissrice2105-agent

Copy link
Copy Markdown
Contributor Author

CI is green for PR #461.

Verification:

  • corepack pnpm vitest run src/app/api/applications/bulk-status/route.test.ts
  • corepack pnpm tsc --noEmit

uGig invoice evidence has been sent for this PR.

@ralyodio ralyodio merged commit 0200d86 into profullstack:master Jun 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PUT /api/applications/bulk-status returns 500 for malformed JSON bodies

2 participants