Skip to content

Return 400 for malformed notification settings JSON#469

Merged
ralyodio merged 1 commit into
profullstack:masterfrom
rissrice2105-agent:codex/notification-settings-invalid-json
Jun 14, 2026
Merged

Return 400 for malformed notification settings JSON#469
ralyodio merged 1 commit into
profullstack:masterfrom
rissrice2105-agent:codex/notification-settings-invalid-json

Conversation

@rissrice2105-agent

Copy link
Copy Markdown
Contributor

Fixes #468.

Changes

  • parse notification settings bodies safely
  • return 400 for malformed or non-object JSON before any upsert
  • add a regression test

Verification

  • corepack pnpm vitest run src/app/api/notification-settings/route.test.ts
  • corepack pnpm tsc --noEmit

@greptile-apps

greptile-apps Bot commented Jun 14, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a readJsonObject helper to the notification-settings PUT handler that safely parses the request body and rejects malformed or non-object JSON with a 400 before any database interaction, accompanied by a regression test.

  • route.ts: new readJsonObject wraps request.json() in a try-catch and rejects arrays, null, primitives, and parse failures, returning null in all invalid cases; the PUT handler now converts that null to an immediate 400 { error: \"Invalid JSON body\" }.
  • route.test.ts: one vitest case verifies the malformed-JSON 400 path and confirms the Supabase from mock is never called; the non-object JSON branches (array, JSON null) and the happy path are not yet tested.

Confidence Score: 4/5

Safe to merge — the core fix is correct and well-scoped, with no risk of regressions to authenticated or happy-path flows.

The readJsonObject helper correctly handles all invalid-body cases (parse errors, arrays, null, primitives), and the 400 is returned before any DB interaction. The test validates the malformed-JSON path and confirms no Supabase call is made. The only gap is that the non-object JSON branches ("null", "[]") and the successful upsert path have no tests, leaving those code paths unverified.

The test file could benefit from additional cases covering valid-but-non-object JSON bodies and the happy path.

Important Files Changed

Filename Overview
src/app/api/notification-settings/route.ts Adds readJsonObject helper that safely parses request JSON, rejecting non-object values (arrays, null, primitives) and malformed JSON; PUT now returns 400 before touching the DB when the body is invalid.
src/app/api/notification-settings/route.test.ts New regression test verifying malformed JSON returns 400 and skips the DB; the non-object JSON branch (array, null, string) and the happy path are not yet covered.

Sequence Diagram

sequenceDiagram
    participant Client
    participant PUT as PUT /api/notification-settings
    participant Auth as getAuthContext
    participant readJson as readJsonObject
    participant DB as Supabase

    Client->>PUT: PUT with JSON body
    PUT->>Auth: getAuthContext(request)
    Auth-->>PUT: null (unauthenticated)
    PUT-->>Client: 401 Unauthorized

    Client->>PUT: PUT with JSON body
    PUT->>Auth: getAuthContext(request)
    Auth-->>PUT: "{ user, supabase }"
    PUT->>readJson: readJsonObject(request)
    Note over readJson: request.json() throws OR result is not a plain object
    readJson-->>PUT: null
    PUT-->>Client: 400 Invalid JSON body

    Client->>PUT: PUT with valid object body
    PUT->>Auth: getAuthContext(request)
    Auth-->>PUT: "{ user, supabase }"
    PUT->>readJson: readJsonObject(request)
    readJson-->>PUT: "Record<string, unknown>"
    PUT->>DB: supabase.upsert(...)
    DB-->>PUT: "{ data, error }"
    PUT-->>Client: "200 { data } or 400 { error }"
Loading

Reviews (1): Last reviewed commit: "Handle malformed notification settings J..." | Re-trigger Greptile

Comment on lines +31 to +38
it("returns 400 for malformed JSON before touching settings", async () => {
const response = await PUT(makePutRequest("{not valid json"));
const body = await response.json();

expect(response.status).toBe(400);
expect(body.error).toBe("Invalid JSON body");
expect(mocks.mockFrom).not.toHaveBeenCalled();
});

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 Non-object JSON paths untested

readJsonObject has two distinct branches that both return null: a JSON parse failure and successfully-parsed JSON that is not an object (array, null, a string, a number). The single test only exercises the parse-failure path. Sending "null" or "[]" hits the !body || typeof body !== "object" || Array.isArray(body) guard and returns the same 400, but neither case is covered. If that guard were ever accidentally dropped, the upsert code would receive an unexpected value and these paths would silently regress.

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!

@rissrice2105-agent

Copy link
Copy Markdown
Contributor Author

CI is green for PR #469.

Verification:

  • corepack pnpm vitest run src/app/api/notification-settings/route.test.ts
  • corepack pnpm tsc --noEmit

uGig invoice evidence has been sent for this PR.

@ralyodio ralyodio merged commit 77aa39c 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/notification-settings returns 500 for malformed JSON

2 participants