Skip to content

feat: render CSV request and response examples - #2869

Merged
makare11a merged 4 commits into
Redocly:mainfrom
rishitank:feat/csv-response-examples
Oct 15, 2026
Merged

makare11a merged 4 commits into
Redocly:mainfrom
rishitank:feat/csv-response-examples

Conversation

@rishitank

@rishitank rishitank commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

What/Why/How?

This picks up #2347 (Response example generation for XML and CSV), which @AlexVarchuk closed after the v3.0.0 release with a request to rebase onto main. The original branch lived in my former employer's fork, which I can no longer push to, so this is a new PR. The rewrite meant a straight rebase wasn't possible, so this is a port to v3's code.

What's left of #2347 for v3

  • XML is already covered in v3. v3 samples every media type, and XML goes through openapi-sampler's XML mode, which handles xml.name, attribute, prefix, namespace and wrapped. I didn't port the old XML generator: it would duplicate that work and give worse output (no attributes, no escaping). I found a few bugs in the sampler's XML mode while comparing, and proposed fixes upstream in fix: xml root element, root arrays and allOf composition openapi-sampler#223.
  • CSV is still missing. A text/csv response shows its generated sample as pretty-printed JSON. This PR adds that.
  • No codeSamplesLanguages option. @adamaltman asked on Response example generation for XML and CSV #2347 whether the format could be worked out from the content type instead of an option. v3 now does that, and so does this PR.

Behaviour

  • In PayloadDisplay, an object payload for a CSV media type is shown as CSV when it is a flat record or an array of flat records. CSV media types are text/csv, application/csv, *+csv, and the legacy x-csv / comma-separated-values, with any parameters. The CSV has a header row (the union of keys across records, in JavaScript property order: first seen, except that integer-like keys such as 10 come first), then one row per record, quoted per RFC 4180.
  • The CSV table is shown in full, like the XML and form-urlencoded views: it isn't cut off at 1,000 characters.
  • This applies to both generated samples and object examples written in the spec. It also covers oneOf variants, through the existing variant picker.
  • Payloads that aren't tabular (nested objects or arrays, primitives, empty) keep the current rendering, so nothing gets worse.
  • String CSV examples are shown as written, as before. langFromMime returns text for CSV, so the code block and copy telemetry report text rather than clike (rendering is unchanged).
  • Edge cases handled:
    • A missing cell under a column named like an Object.prototype member (e.g. constructor) stays empty, and an own __proto__ key is an ordinary column.
    • An empty cell in a single-column table is written as "", so the row doesn't become a blank line.

Example (text/csv, schema array of {date, keyword, clicks} where keyword has the example shoes, red):

date,keyword,clicks
2019-08-24,"shoes, red",0

Before this change, the same response showed [ { "date": "2019-08-24", "keyword": "shoes, red", "clicks": 0 } ].

Reference

Tests

  • New src/utils/__tests__/csv.test.ts (21 tests):
    • quoting, header union and missing cells
    • null/undefined values
    • prototype-named columns (including an own __proto__ key) and single-column empty cells
    • every non-tabular fallback
    • the allOf/oneOf/$ref fixtures from Response example generation for XML and CSV #2347, run through openapi-sampler
  • media-type.test.ts: isCsvMediaType (case, parameters, +csv, legacy aliases, negatives) and langFromMime for CSV.
  • PayloadDisplay.test.tsx: CSV for text/csv (with charset), application/csv and +csv; a long table shown untruncated; the JSON fallback for nested data; string CSV as plain text.
  • npm run lint, npm run ts:check and npm run unit pass: 3,286 tests.
  • npm run e2e: 310 passed, 2 failed. The two failures (download.spec.ts › GraphQL: should download schema and scroll-anchoring.spec.ts › Scroll-spy URL sync) also fail on an unmodified main in my environment, where outbound requests to cdn.redoc.ly are blocked. Neither touches examples.
  • Checked by hand in a standalone build in Chromium: the text/csv response renders as above.

Check yourself

  • Code is linted
  • Tested
  • All new/updated code is covered with tests

🤖 Generated with Claude Code

https://claude.ai/code/session_01117LuacuBxMJUn1wJkfdyL

rishitank and others added 3 commits October 14, 2026 17:00
For text/csv (and application/csv, +csv, x-csv, comma-separated-values)
media types, PayloadDisplay now renders a flat record, or an array of
flat records, as CSV: a header row plus RFC 4180-quoted rows. Payloads
that are not tabular keep the previous rendering. String CSV examples are
shown as plain text instead of C-like highlighting.

Re-contributes the CSV half of Redocly#2347 for v3. The format is derived from
the media type, so the codeSamplesLanguages option is no longer needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01117LuacuBxMJUn1wJkfdyL
Completes the previous commit, which only added the CSV unit tests:
PayloadDisplay now uses jsonToCsv for CSV media types, with tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01117LuacuBxMJUn1wJkfdyL
@rishitank
rishitank requested a review from a team as a code owner October 14, 2026 16:08
Generated CSV tables are no longer cut at MAX_DISPLAYED_STRING_LENGTH,
matching the XML and form-urlencoded views. The changeset no longer claims
string CSV examples changed: clike already rendered as plain text. Documents
LF row separators and the absence of formula-injection escaping, and tests
an own __proto__ key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01117LuacuBxMJUn1wJkfdyL

@makare11a makare11a 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.

lgtm

@makare11a
makare11a merged commit d6d785f into Redocly:main Oct 15, 2026
4 checks passed
@makare11a

Copy link
Copy Markdown
Contributor

Merged! Thank you for your contribution @rishitank. The changes will be available in the next release

rishitank added a commit to rishitank/rishitank that referenced this pull request Oct 15, 2026
Redocly/redoc#2347 (2023) was closed when Redoc v3 shipped. Its CSV half
was re-raised against v3 as Redocly/redoc#2869 and merged on 15 Oct 2026;
the XML half became fixes to openapi-sampler, Redocly/openapi-sampler#223,
still in review. Same wording as the portfolio's open-source card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01117LuacuBxMJUn1wJkfdyL
@rishitank
rishitank deleted the feat/csv-response-examples branch October 15, 2026 15:09
rishitank added a commit to rishitank/rishitank that referenced this pull request Oct 15, 2026
…es await review (#2)

The Redoc line still described the 2023 PR (Redocly/redoc#2347) as open.
It now says the examples were first proposed in 2023 and later requested by
other developers, CSV is merged into v3 for the next release
(Redocly/redoc#2869, merged 15 Oct 2026, after redoc@3.0.1), and the XML
fixes to openapi-sampler await review (Redocly/openapi-sampler#223).

Reviewed by CodeRabbit (approved 564170d) and an independent Claude
fact-check of every claim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01117LuacuBxMJUn1wJkfdyL
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.

2 participants