fix(reviews): validate limit/offset/gig_id, log errors, expose validation issues (matches #387-#390)#391
Conversation
Greptile SummaryThis PR adds input validation for
Confidence Score: 3/5Safe to merge for the validation improvements, but the POST handler's catch block in reviews/route.ts was not updated and still silently swallows unexpected errors with no logging — exactly the problem this PR set out to fix. The GET path in reviews is correctly hardened and the Supabase error paths now log. However, the POST handler's catch {} block — which covers a large surface including reputation hooks, email sending, webhook dispatch, and notification inserts — still has no error binding and no console.error. Any crash in that path produces a silent 500 in production. The unused parsePaginationParam import is also a build-time concern if the project has strict no-unused-imports linting. src/app/api/reviews/route.ts — the POST handler catch block needs the same logging treatment applied to the GET handler Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant GET /api/reviews
participant POST /api/reviews
participant Supabase
Client->>GET /api/reviews: ?gig_id=X&limit=Y&offset=Z
GET /api/reviews->>GET /api/reviews: Validate gig_id (UUID regex)
GET /api/reviews->>GET /api/reviews: Validate limit (>= 1, integer, cap 50)
GET /api/reviews->>GET /api/reviews: Validate offset (>= 0, integer, cap 100k)
alt Invalid param
GET /api/reviews-->>Client: 400 { error: "..." }
else Valid
GET /api/reviews->>Supabase: SELECT reviews WHERE gig_id=X LIMIT Y OFFSET Z
Supabase-->>GET /api/reviews: data | error
alt Supabase error
GET /api/reviews->>GET /api/reviews: console.error (logged)
GET /api/reviews-->>Client: 400 { error: message }
else Success
GET /api/reviews-->>Client: 200 { data, pagination }
end
end
Client->>POST /api/reviews: { gig_id, reviewee_id, rating, comment }
POST /api/reviews->>POST /api/reviews: Zod schema validation
alt Invalid body
POST /api/reviews-->>Client: 400 { error: "Invalid review payload", issues: [...] }
else Valid
POST /api/reviews->>Supabase: INSERT review
Supabase-->>POST /api/reviews: data | error
alt Supabase error
POST /api/reviews->>POST /api/reviews: console.error (logged)
POST /api/reviews-->>Client: 400 { error: message }
else Unexpected exception
POST /api/reviews->>POST /api/reviews: catch{} NOT logged
POST /api/reviews-->>Client: 500 { error: "An unexpected error occurred" }
else Success
POST /api/reviews-->>Client: 201 { data: review }
end
end
|
| { | ||
| error: parsed.error.issues[0].message, | ||
| issues: parsed.error.issues, | ||
| }, |
There was a problem hiding this comment.
Bounties POST still exposes only the first Zod issue as
error
The reviews POST was updated to use a generic "Invalid review payload" string so the issues array is the authoritative source of failures. The bounties POST was only half-updated — it now includes issues in the response body, but the top-level error field still shows issues[0].message. This makes the error contract inconsistent across the two endpoints and means clients who read only error still miss all but the first validation failure.
| { | |
| error: parsed.error.issues[0].message, | |
| issues: parsed.error.issues, | |
| }, | |
| { | |
| error: "Invalid bounty payload", | |
| issues: parsed.error.issues, | |
| }, |
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!
Bug Fix: /api/reviews input validation
Continuation of #387 (bounties), #388 (gigs), #389 (notifications), #390 (activity). This PR applies the same input validation pattern to /api/reviews.
Bugs Found
Bug 1:
?limit=abcreturns 200parseInt("abc", 10)returnsNaN. Falls back to default 20 silently.Bug 2:
?limit=99999returns 200No upper bound validation, silently capped at 50.
Bug 3:
?limit=0returns 200Should be 400 - limit must be >= 1.
Bug 4:
?offset=-1returns 200Should be 400 - offset must be >= 0.
Bug 5:
?gig_id=not-a-uuidreturns 200No UUID validation. Supabase query is sent unfiltered, returns empty array, but client receives 200 OK with no error feedback.
Bug 6: POST validation returns only first issue
Returns only the first Zod issue, masking all other validation problems. Should return full
issuesarray.Bug 7: Generic 500 errors with no logging
The catch block returns "An unexpected error occurred" with no
console.error.Changes
limit: must be positive integer (>= 1), returns 400 otherwise.offset: must be non-negative integer (>= 0), returns 400 otherwise.gig_idas UUID v4 with regex (returns 400 if invalid).issuesarray (not just first).console.errorlogging for both Supabase errors and unexpected errors.Testing
Related
src/app/api/reviews/route.ts)Looking forward to your review.