Skip to content

fix: follow up moderations API review feedback#1952

Open
steebchen-bot wants to merge 1 commit into
mainfrom
fix-moderations-followup
Open

fix: follow up moderations API review feedback#1952
steebchen-bot wants to merge 1 commit into
mainfrom
fix-moderations-followup

Conversation

@steebchen-bot
Copy link
Copy Markdown
Collaborator

@steebchen-bot steebchen-bot commented Apr 2, 2026

Summary

  • tighten /v1/moderations multimodal validation so text and image_url payloads are required by type
  • normalize moderation proxy errors to the documented OpenAPI contract and collapse undocumented upstream statuses to 502
  • clarify the moderations guide wording and add moderation endpoint regressions for invalid multimodal input and unsupported upstream statuses

Verification

  • pnpm exec prettier --check apps/gateway/src/moderations/moderations.ts apps/gateway/src/api.spec.ts apps/docs/content/features/moderations.mdx
  • node - <<'NODE' ... typescript transpileModule check for apps/gateway/src/moderations/moderations.ts and apps/gateway/src/api.spec.ts ... NODE

Notes

  • pnpm exec vitest run apps/gateway/src/api.spec.ts is blocked in this checkout because the workspace packages such as @llmgateway/db are not resolvable until the broader workspace build/setup issue is addressed.
  • pnpm --filter gateway build currently fails for the same pre-existing workspace package-resolution problem, and pnpm --filter docs build depends on the missing apps/gateway/openapi.json artifact from that build.

Summary by CodeRabbit

  • Documentation

    • Updated moderation input documentation to clarify type-specific required fields for multimodal content items.
  • Bug Fixes

    • Enhanced validation for multimodal moderation inputs with stricter field requirements based on content type.
    • Improved error response handling and consistency in API responses to upstream errors.
  • Tests

    • Added comprehensive test coverage for multimodal input validation and error handling scenarios.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 2, 2026

Walkthrough

This 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

Cohort / File(s) Summary
Documentation
apps/docs/content/features/moderations.mdx
Updated input field documentation from a generic multimodal array description to a type-driven structure where each item contains only fields relevant to its type value (e.g., text for text items, image_url for image items).
Tests
apps/gateway/src/api.spec.ts
Added test cases validating invalid moderation input (missing required field with given type) returns 400 error before upstream call, and testing upstream 418 status handling with error normalization and moderation log entry recording.
Moderation Implementation
apps/gateway/src/moderations/moderations.ts
Replaced type union with discriminated union schema for stricter input validation; added .strict() enforcement on item objects; expanded error response schema to allow optional type, param, code fields; introduced error normalization helper mapping unexpected statuses to 502 and reshaping raw upstream error payloads into consistent { error: { message, type, param, code } } structure.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • smakosh
  • steebchen
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: follow up moderations API review feedback' directly addresses the main changes: tightening validation for the moderations API, normalizing error responses, and implementing feedback from a prior review.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-moderations-followup

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/gateway/src/api.spec.ts (1)

201-228: Restore the fetch spy to ensure test isolation.

The fetchSpy is created but never cleaned up. While this test doesn't mock fetch (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

📥 Commits

Reviewing files that changed from the base of the PR and between 2c4ebfc and c1dee72.

📒 Files selected for processing (3)
  • apps/docs/content/features/moderations.mdx
  • apps/gateway/src/api.spec.ts
  • apps/gateway/src/moderations/moderations.ts

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.

1 participant