fix: follow up moderations API review feedback#1952
Conversation
WalkthroughThis pull request strengthens the moderation endpoint by implementing stricter input validation through discriminated union schemas, adding upstream error normalization logic with a status allowlist, and expanding test coverage for both validation failures and upstream error scenarios. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Gateway
participant Validator as Input Validator
participant Upstream as Moderation Service
participant Logger as Moderation Logger
Client->>Gateway: POST /v1/moderations (multimodal input)
Gateway->>Validator: Validate input against discriminated union schema
alt Invalid Input (missing required field)
Validator-->>Gateway: Validation error
Gateway-->>Client: HTTP 400 + invalid_request_error
else Valid Input
Validator-->>Gateway: Validation passed
Gateway->>Upstream: Forward request
alt Upstream OK (200)
Upstream-->>Gateway: Moderation result
Gateway->>Logger: Record success log
Gateway-->>Client: HTTP 200 + result
else Upstream Error (e.g., 418)
Upstream-->>Gateway: Error response (raw string or unknown shape)
Gateway->>Gateway: Normalize status & error payload
Gateway->>Logger: Record error log (hasError: true, statusCode: 418)
Gateway-->>Client: HTTP 502 + normalized error object
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/gateway/src/api.spec.ts (1)
201-228: Restore the fetch spy to ensure test isolation.The
fetchSpyis created but never cleaned up. While this test doesn't mockfetch(only asserts it wasn't called), leaving the spy active can interfere with subsequent tests in the suite.♻️ Proposed fix to restore the spy
test("/v1/moderations rejects invalid multimodal items before proxying upstream", async () => { const fetchSpy = vi.spyOn(globalThis, "fetch"); - const res = await app.request("/v1/moderations", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - input: [ - { - type: "text", - }, - ], - }), - }); - - expect(res.status).toBe(400); - expect(await res.json()).toEqual({ - error: { - message: "Invalid request parameters", - type: "invalid_request_error", - param: null, - code: "invalid_parameters", - }, - }); - expect(fetchSpy).not.toHaveBeenCalled(); + try { + const res = await app.request("/v1/moderations", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + input: [ + { + type: "text", + }, + ], + }), + }); + + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ + error: { + message: "Invalid request parameters", + type: "invalid_request_error", + param: null, + code: "invalid_parameters", + }, + }); + expect(fetchSpy).not.toHaveBeenCalled(); + } finally { + fetchSpy.mockRestore(); + } });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/gateway/src/api.spec.ts` around lines 201 - 228, The test " /v1/moderations rejects invalid multimodal items before proxying upstream" creates a spy (fetchSpy) on globalThis.fetch but never restores it; restore the spy at the end of the test (or wrap the test body in try/finally) by calling fetchSpy.mockRestore() (or equivalent vi.restoreAllMocks() cleanup) after the assertions to ensure the global fetch is returned to its original implementation and prevent cross-test interference.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/gateway/src/api.spec.ts`:
- Around line 201-228: The test " /v1/moderations rejects invalid multimodal
items before proxying upstream" creates a spy (fetchSpy) on globalThis.fetch but
never restores it; restore the spy at the end of the test (or wrap the test body
in try/finally) by calling fetchSpy.mockRestore() (or equivalent
vi.restoreAllMocks() cleanup) after the assertions to ensure the global fetch is
returned to its original implementation and prevent cross-test interference.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 83aa57fb-76e3-4709-a219-06f3a5ab802d
📒 Files selected for processing (3)
apps/docs/content/features/moderations.mdxapps/gateway/src/api.spec.tsapps/gateway/src/moderations/moderations.ts
Summary
/v1/moderationsmultimodal validation sotextandimage_urlpayloads are required by type502Verification
pnpm exec prettier --check apps/gateway/src/moderations/moderations.ts apps/gateway/src/api.spec.ts apps/docs/content/features/moderations.mdxnode - <<'NODE' ... typescript transpileModule check for apps/gateway/src/moderations/moderations.ts and apps/gateway/src/api.spec.ts ... NODENotes
pnpm exec vitest run apps/gateway/src/api.spec.tsis blocked in this checkout because the workspace packages such as@llmgateway/dbare not resolvable until the broader workspace build/setup issue is addressed.pnpm --filter gateway buildcurrently fails for the same pre-existing workspace package-resolution problem, andpnpm --filter docs builddepends on the missingapps/gateway/openapi.jsonartifact from that build.Summary by CodeRabbit
Documentation
Bug Fixes
Tests