Skip to content

fix(api): restore OpenAPI response validation behind a flag - #3522

Open
Gauvino wants to merge 1 commit into
seerr-team:developfrom
Gauvino:fix-openapi-response-validation
Open

Gauvino wants to merge 1 commit into
seerr-team:developfrom
Gauvino:fix-openapi-response-validation

Conversation

@Gauvino

@Gauvino Gauvino commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Description

Streamyfin is a Jellyfin client with a Seerr integration. It takes its types from a fork of the server pulled in as a submodule, because the spec does not match the responses. Moving it onto the published spec is what turned this up.

validateResponses: true was dropped in 96f3861c, the bump to express-openapi-validator v4.8.0, when the call moved from new OpenApiValidator().install() to OpenApiValidator.middleware(). Nothing has checked a response against seerr-api.yml since, which is how the spec got to where #3298 found it. The workaround comment for it is still under the validator, guarding nothing.

Switching it straight back on would be rough after six years of drift, so it only runs with VALIDATE_API_RESPONSES=true, and it logs through onError instead of throwing. The response is still served, with one exception that comes from the validator's own response wrapper: a null JSON body becomes a 204. Nothing in server/routes sends one today. The Cypress job sets it, so the drift shows up in CI without failing anything.

It won't catch a property that is served and not declared, since none of our schemas set additionalProperties: false. It catches missing required properties, wrong types and nullability.

Related to #3298.

AI Disclosure: AI-assisted throughout. I used Claude Code (Opus 5, max effort) to trace the regression through the git history, to measure a live server against the spec, to write the patch, and to run the build and the test suite. I reviewed all of it, and this description started as its draft and was edited by me.

How Has This Been Tested?

Built in a node:22 container, seeded with pnpm cypress:prepare, run with the flag. Signing in as the seeded admin catches one straight away:

[warn][OpenAPI]: Response does not match the API specification
{"method":"POST","path":"/api/v1/auth/local","errors":[{"path":"/response/email",
"message":"must have required property 'email'","errorCode":"required.openapi.validation"}]}

POST /auth/local sends the user through filter(), which strips email, against a schema that declares it required. Still answered 200.

Without the flag the same requests log nothing, so the default path is unchanged.

pnpm test is 189 passing before and after. pnpm build passes.

Screenshots / Logs (if applicable)

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • New Features

    • Added optional API response validation against the published API specification.
    • Validation mismatches are logged with the request method and path while responses continue to be served.
  • Documentation

    • Added contributor guidance for enabling response validation during development and testing.
  • Tests

    • Cypress runs now enable response validation to report specification mismatches without failing the test run.

@Gauvino
Gauvino requested a review from a team as a code owner September 18, 2026 13:21
Copilot AI lite review requested due to automatic review settings September 18, 2026 13:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 19eb6deb-cd5c-42e1-b141-818111b3badf

📥 Commits

Reviewing files that changed from the base of the PR and between 38beec2 and 67dc180.

📒 Files selected for processing (3)
  • .github/workflows/cypress.yml
  • CONTRIBUTING.md
  • server/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • CONTRIBUTING.md

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

The server enables OpenAPI response validation only when VALIDATE_API_RESPONSES=true. Validation mismatches are logged without blocking responses. Cypress enables the setting, and contributor documentation describes the behavior.

Changes

API response validation

Layer / File(s) Summary
Configure and document response validation
server/index.ts, .github/workflows/cypress.yml, CONTRIBUTING.md
The server reads VALIDATE_API_RESPONSES and logs validation errors while serving responses. Cypress enables validation, and contributor guidance documents the environment variable and known response differences.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: fallenbagel, gauthier-th

Merge Risk: ⚪ Minimal · up to 67dc1

Response mismatches are logged while responses remain available, and the validation flag is correctly enabled for Cypress diagnostics.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: restoring OpenAPI response validation behind the VALIDATE_API_RESPONSES flag.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

A rabbit reads each line,
The patch grows clear beneath the moon,
Small changes hop in place,
Tests guard the garden path,
Reviews bloom before the dawn.

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

@Gauvino
Gauvino force-pushed the fix-openapi-response-validation branch from 38beec2 to b243890 Compare September 18, 2026 13:59
Response validation was installed in September 2020 and lost three months
later in 96f3861, the upgrade to express-openapi-validator v4.8.0: the
move from `new OpenApiValidator().install()` to `OpenApiValidator.middleware()`
did not carry `validateResponses` over. The workaround comment that exists
for it is still in server/index.ts, six years later, with nothing left to
guard.

It comes back off by default, because a schema that has drifted from its
handler would otherwise turn a working endpoint into a 500. With
VALIDATE_API_RESPONSES=true a mismatch is logged and the response is still
served, so the spec can be brought back in line one endpoint at a time.
The Cypress job sets it, so the drift is reported on every run without
failing anything.

The logged paths drop their query string. The validator reports an
undocumented status code with req.originalUrl as the error path, which
would otherwise put a search term in a log file that the Logs page copies
to the clipboard.
@Gauvino
Gauvino force-pushed the fix-openapi-response-validation branch from b243890 to 67dc180 Compare September 18, 2026 14:03

@fallenbagel fallenbagel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I have not reviewed this but from a quick look at the PR, there are a few details that violate our contributing guidelines, and we haven't made exceptions for it in the past either, so just wanted to flag it.

While we do appreciate the detail in the AI disclosure, since it's more specific than most we get here, read against our policy it describes Claude Code doing the actual implementation work, which is a violation of our contributing guidelines' AI policy. Claude Code traced the regression through git history, measured a live server against the spec, wrote the patch, and ran the build and tests, with your review coming afterward.

Our contributing guideline's AI assistance notice asks for AI-assisted development, where AI is used as a tool to assist with development that you are actually doing, not AI-driven development where the model is doing the implementation and you are reviewing the result. Reviewing or testing an AI-generated implementation afterward doesn't move a contribution from one category to the other. How clean the resulting diff reads doesn't change that either.

The same notice also expects PR descriptions to be your own words. The disclosure says this description started as Claude's draft and was edited by you, which is the same issue. An edited AI draft isn't a description written by you, no matter how much editing happened. Writing the PR description yourself takes a few minutes, so please just write it yourself next time.

To keep this open, I'd like to understand your reasoning around a couple of things the PR text doesn't already spell out. If an endpoint started returning a genuinely empty body on purpose, would the 204 rewrite mask that being wrong, or would it still catch it? And why log at warn rather than error, given the response is served either way?

If the intention is to have Claude do the implementation and then have you review what it produced, though, that's not something we can accept as a contribution here. At that point the implementation is being outsourced to the model rather than being your work with AI assisting you. If that's the workflow you want to use, that's fine, but those contributions will be closed without review under our existing guidelines for this repository.

This branch has not been deployed

No deployments
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.

3 participants