Skip to content

Render OpenAPI request/response examples from per-property examples#18629

Draft
djgrove wants to merge 1 commit intomasterfrom
devon/openapi-examples-spike
Draft

Render OpenAPI request/response examples from per-property examples#18629
djgrove wants to merge 1 commit intomasterfrom
devon/openapi-examples-spike

Conversation

@djgrove
Copy link
Copy Markdown
Member

@djgrove djgrove commented Apr 20, 2026

Summary

Reintroduces cURL request bodies and example response JSON on the generated REST API pages, previously removed in #18551.

Reads route-level examples from the native OpenAPI 3 mediaType.example slot : no Hugo-side synthesis, no traversal of schema property trees. The upstream service spec populates that slot via @PulumiRouteProperty(requestExample = """...""", responseExample = """...""") text blocks (pulumi/pulumi-service#41680). Whatever shows up in the spec is what renders.

What this changes

  • layouts/partials/openapi/endpoint.html: uncomments the template "openapi/request-example.html" and template "openapi/examples.html" call sites that were disabled in Generate REST API docs from live OpenAPI spec #18551.
  • layouts/partials/openapi/request-example.html: renders a cURL block with --data '...' when the operation's application/json request body has an example; otherwise renders the cURL without a body.
  • layouts/partials/openapi/examples.html: renders application/json response example (or iterates examples if plural is used) as pretty JSON.

Total: one file deleted (the prior-draft synthesizer), three edited.

Not in this PR

  • Populating examples in the spec : that's upstream in pulumi/pulumi-service#41680.
  • The convention doc describing how service-side authors should write text-block examples : also in pulumi/pulumi-service#41680.

Draft

Held as draft until the service-side PR (pulumi/pulumi-service#41680) lands and the public spec starts carrying route-level examples. Once that ships, this PR becomes a mechanical "turn it on" merge.

🤖 Generated with Claude Code

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 20, 2026

Review

Template-only change — no doc content to style-check. Scope: correctness, maintainability, and behavioral changes in the four layouts/partials/openapi/*.html files.

The refactor is coherent, well-commented, and the synthesize-example.html partial is genuinely nice — the Map/List-as-JSON-string quirk and the .json-filename workaround for transform.Unmarshal's CSV misfire are documented right where a future reader will need them. A few small concerns worth considering before this comes out of draft.

Concerns

1. synthesize-example.html (≈line 24): no oneOf / anyOf handling

The walker handles \$ref, allOf, object, array, and leaf example. If any schema in the public spec uses oneOf or anyOf (common for union/discriminator types), properties typed that way will silently render no example, and their parent object will either omit them or fall through to "nothing synthesized." Worth confirming the Pulumi spec doesn't use these — or adding a branch that picks the first variant.

2. synthesize-example.html lines 21–25: \$ref resolution doesn't validate the pointer target

{{ $refParts := split (index $schema \"\$ref\") \"/\" }}
{{ $refName := index $refParts (sub (len $refParts) 1) }}
{{ with index $openapi.components.schemas $refName }}

This assumes every \$ref points into #/components/schemas/. A ref to e.g. #/components/parameters/Foo where schemas.Foo also exists would silently mis-resolve to the wrong schema. Low risk for the Pulumi spec, but a prefix check (hasPrefix (index \$schema \"\$ref\") \"#/components/schemas/\") would make this defensive.

3. examples.html line 7 vs. line 8: subtle behavior change worth calling out

    {{ if .example }}
        <h5>Example</h5>
        <pre><code style=\"flex-wrap: nowrap; overflow-x: scroll;\">{{ .example | jsonify (dict \"indent\" \"  \") }}</code></pre>
    {{ else if .examples }}

Previously .example and .examples would both render if both were present; now they're mutually exclusive via else if. OpenAPI 3 says they're supposed to be mutually exclusive, so this is more correct — just flagging that the behavior change isn't in the PR description.

4. request-example.html lines 33–46: POST-with-no-body produces an odd curl

For a non-GET operation with no requestBody or a schema that synthesizes nothing, the first branch still runs:

-H \"Content-Type: application/json\"
...
  https://api.pulumi.com/...

…so you get a POST/PUT/DELETE that declares a JSON content type with no --data. Harmless but a little weird. Consider suppressing Content-Type when \$bodyData is empty, or dropping into the simpler GET-style block.

5. request-example.html lines 34–46 and 49–55: duplicated curl construction

The two branches duplicate the slice \"curl \\\\\" / Accept / Authorization / \$url scaffolding. Could fold shared lines into one slice and append the method/body lines conditionally — would make the method/body-present matrix easier to reason about and avoids the risk of the two branches drifting.

6. synthesize-example.html line 45: SHA-based resource filenames accumulate

resources.FromString \"openapi-examples/%s.json\" is the right trick, but every unique Map/List example becomes a persistent in-memory resource for the build. Fine in practice; mentioning for future awareness if the spec grows very large.

Non-blocking nits

  • synthesize-example.html line 19: le \$depth 8 allows depth 0–8 (9 levels). Matches the header comment ("bails out above 8"), so this is consistent — but 8 is a magic number; a named \$maxDepth would read better.
  • The inline style=\"flex-wrap: nowrap; overflow-x: scroll;\" is repeated in three places across examples.html. Pre-existing; worth a CSS class someday.

Draft status

PR description already notes this lands as a no-op until upstream Java annotations populate example fields — no action needed there. Once spec coverage exists, the test-plan items cover the right ground (nested \$ref, Map/List parsing, no-example regression).


Mention @claude if you'd like another pass after changes.

@pulumi-bot
Copy link
Copy Markdown
Collaborator

pulumi-bot commented Apr 20, 2026

@pulumi-bot
Copy link
Copy Markdown
Collaborator

pulumi-bot commented Apr 20, 2026

Lighthouse Performance Report

Commit: e9c2532 | Metric definitions

Page Device Score FCP LCP TBT CLS SI
Homepage Mobile 🟡 71 2.6s 2.6s 859ms 0.010 4.4s
Homepage Desktop 🟢 95 0.8s 1.0s 21ms 0.080 1.5s
Install Pulumi Mobile 🔴 35 4.6s 6.0s 330ms 0.431 7.4s
Install Pulumi Desktop 🟢 90 1.2s 1.5s 24ms 0.020 1.7s
AWS Get Started Mobile 🟡 53 4.5s 5.9s 344ms 0.085 7.4s
AWS Get Started Desktop 🟢 92 1.1s 1.4s 24ms 0.025 1.6s

Reintroduces cURL request bodies and example response JSON on the
generated REST API pages. Reads route-level examples from the native
OpenAPI 3 mediaType.example slot, which the upstream service spec now
populates via @PulumiRouteProperty(requestExample / responseExample)
text blocks (see pulumi/pulumi-service#41680).

No Hugo-side synthesis: the authoritative example shape lives in the
spec, rendered as-is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@djgrove djgrove force-pushed the devon/openapi-examples-spike branch from 31d3041 to e9c2532 Compare April 22, 2026 02:42
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