openapi3: add an OpenAPI 3.0 output package - #117
Merged
Conversation
Ports the openapi2 writer to OpenAPI 3.0.3. The docparse IR is format-neutral, so the parser is untouched and both writers share it. Mappings: - body parameter -> requestBody with a content map - form parameters -> requestBody, application/x-www-form-urlencoded - consumes/produces -> per-media-type content entries - definitions -> components.schemas - #/definitions/X -> #/components/schemas/X - flat parameter fields -> parameter.schema - basepath -> servers Two OpenAPI 2 workarounds are dropped rather than ported: query array items keep their $ref instead of being downgraded to string, and a parameter typed by a named Go type keeps that reference. Response codes are string keys, and a response with no description falls back to the HTTP status text, both of which OpenAPI 3 requires.
Covers the example package end to end and asserts no OpenAPI 2 constructs survive, plus the schema, status-text and id helpers.
Adds openapi3-yaml, openapi3-json and openapi3-jsonindent. The default output stays openapi2-yaml.
TestOpenAPI3 reuses the existing testdata packages and compares against want3.yaml, so only curated cases run. Set UPDATE_GOLDEN=1 to refresh them.
shane-tw
approved these changes
Aug 10, 2026
rafaeljusto
approved these changes
Aug 10, 2026
A response documented as a content type with no body, e.g.
Response 200 (text/csv): {empty}
recorded that type in the OpenAPI 2 operation-level `produces`. OpenAPI 3
has no `produces`, and the writer only emitted `content` when there was a
schema, so the media type was dropped and the response looked empty.
Emit a schema-less content entry for it instead. Only explicit non-default
types qualify, so responses that merely default to JSON without a body,
such as 204s, stay bare.
Coverage Report for CI Build 31419661334Coverage increased (+1.5%) to 56.68%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an
openapi3output package, so Kommentaar can emit OpenAPI 3.0.3alongside the existing Swagger 2.0 output.
New output formats:
openapi3-yaml,openapi3-json,openapi3-jsonindent.The default output is unchanged (
openapi2-yaml), so nothing moves until acaller asks for v3.
docparseis untouched. The IR is already format-neutral JSON Schema, so bothwriters share the same parser and the same
Schematype.Mapping
in: bodyparameterrequestBodywith acontentmaprequestBody,application/x-www-form-urlencodedconsumes/producescontententriesdefinitionscomponents.schemas#/definitions/X#/components/schemas/Xtype,format,enum, …)parameter.schemabasepathserversTwo OpenAPI 2 workarounds are dropped rather than ported, because v3 gives
parameters a full schema:
$refinstead of being downgraded tostring(
openapi2.gohad// in swagger 2.0, arrays in the query can only contain basic type)back to
stringTwo things v3 requires and v2 did not:
"200", not200)descriptionis mandatory on a response, so an empty one falls back to theHTTP status text
Verification
Beyond the unit tests and 13 golden files, I generated the full
Teamwork Projects API v3 spec with both writers and compared them
structurally (620 paths, 793 operations, 1010 schemas):
$refprefix — 0 of 1010 differname+insets:0 differences
in: bodybecame 249requestBody, with 0 presence mismatchesswagger:,definitions:,#/definitions/,in: body,in: formData,consumes,producesValidated with
spectral(spectral:oas) against that real spec, the v3output is strictly more valid than the Swagger 2.0 we ship today:
parser*-valid-schema-examplepath-params*-schemaThe 1392
parsererrors v3 eliminates are all "Mapping key must be a stringscalar rather than number" — the unquoted integer response codes.
The errors that remain are pre-existing and reproduce identically under both
writers:
*-valid-schema-example:Schema.Defaultis a GostringandEnumis[]string, so a boolean parameter emitsdefault: "false"and aninteger enum emits
["0","1","2","3"]. Fixing this belongs indocparseandwould improve both writers.
path-params: duplicate endpoints documented under two placeholdernames. A caller-side doc-comment bug.
type: "any": existingdocparseoutput.Fidelity audit against a real spec
I diffed the two writers field by field over the Teamwork Projects API v3 spec —
every parameter's
type,format,enum,default,minimum,maximum,readOnly,itemsanddescription; every response's description, schemareference and media type; every request body; every schema body; and the
operation metadata.
That audit found one real fidelity loss, now fixed in this PR:
A response documented as a media type with no body —
Response 200 (text/csv): {empty}— recordedtext/csvin the OpenAPI 2operation-level
produces. OpenAPI 3 has noproduces, and the writer onlyemitted
contentwhen a schema existed, so the media type vanished and theresponse looked empty. 42 endpoints were affected (CSV, HTML, PDF, XLSX, plain
text, octet-stream). They now emit a schema-less content entry:
Only explicit non-default media types qualify, so the 158
204s and theother ~580 schema-less JSON responses stay bare rather than gaining a
meaningless
application/json: {}.After the fix the audit reports zero differences in every other category:
no parameter field lost, no enum/default/format dropped, no schema body
changed, no operation or response missing, no description lost.
spectralerror counts are unchanged by the fix (1889), so the new entries introduce no
validation problems.
Note for callers
Extend:stays a verbatim passthrough. An extend file written for v2 (e.g.containing
consumes:) will emit a key that is not valid in OpenAPI 3;x--prefixed extensions are unaffected.Testing
go test ./...passes, including the newopenapi3package.TestOpenAPI3reuses the existing testdata packages and only runs cases that have a
want3.yaml, so it adds no fixture duplication. Refresh goldens withUPDATE_GOLDEN=1 go test -run TestOpenAPI3 .