diff --git a/changelogs/internal/newsfragments/1749.clarification b/changelogs/internal/newsfragments/1749.clarification new file mode 100644 index 000000000..54c042854 --- /dev/null +++ b/changelogs/internal/newsfragments/1749.clarification @@ -0,0 +1 @@ +Templates: add support for reference objects in parameters. diff --git a/layouts/partials/json-schema/resolve-refs.html b/layouts/partials/json-schema/resolve-refs.html index 1d99201db..425e5577d 100644 --- a/layouts/partials/json-schema/resolve-refs.html +++ b/layouts/partials/json-schema/resolve-refs.html @@ -7,6 +7,14 @@ rather than a normal `dict` because with `dict` you can't replace key values: https://discourse.gohugo.io/t/how-can-i-add-set-and-delete-keys-in-a-dictionary/29661 + XXX: This partial should be phased out, and replaced with + `openapi/resolve-ref-object`. OpenAPI 3 doesn't really allow arbitrary JSON + references. As [swagger.io] says: "A common misconception is that `$ref` is + allowed anywhere in an OpenAPI specification file. Actually `$ref` is only + allowed in places where the OpenAPI 3.0 Specification explicitly states that + the value may be a reference." + + [swagger.io]: https://swagger.io/docs/specification/using-ref/#allowed-places */}} {{ $schema := .schema }} diff --git a/layouts/partials/openapi/render-parameters.html b/layouts/partials/openapi/render-parameters.html index 925b01979..c15479061 100644 --- a/layouts/partials/openapi/render-parameters.html +++ b/layouts/partials/openapi/render-parameters.html @@ -3,8 +3,9 @@ Render the parameters of a given type, given: * `parameters`: OpenAPI data specifying the parameters - * `type`: the type of parameters to render: "header, ""path", "query" + * `type`: the type of parameters to render: "header", "path", "query" * `caption`: caption to use for the table + * `path`: the path where this definition was found, to enable us to resolve "$ref" This template renders a single table containing parameters of the given type. @@ -13,14 +14,18 @@ {{ $parameters := .parameters }} {{ $type := .type }} {{ $caption := .caption }} - -{{ $parameters_of_type := where $parameters "in" $type }} - -{{ with $parameters_of_type }} - - {{/* build a dict mapping from name->parameter, which render-object-table expects */}} - {{ $param_dict := dict }} - {{ range $parameter := . }} +{{ $path := .path }} + +{{/* build a dict mapping from name->parameter, which render-object-table expects */}} +{{ $param_dict := dict }} + +{{ range $parameter := $parameters }} + {{/* + Per https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#operation-object: + the parameters can be reference objects; resolve them now. + */}} + {{ $parameter = partial "openapi/resolve-ref-object" (dict "schema" $parameter "path" $path) }} + {{ if (eq $parameter.in $type) }} {{/* merge the schema at the same level as the rest of the other fields because that is what `render-object-table` expects. Put the schema first so examples in it are @@ -29,8 +34,7 @@ {{ $param := merge $parameter.schema $parameter }} {{ $param_dict = merge $param_dict (dict $parameter.name $param )}} {{ end }} - - {{/* and render the parameters */}} - {{ partial "openapi/render-object-table" (dict "title" $caption "properties" $param_dict) }} - {{ end }} + +{{/* and render the parameters */}} +{{ partial "openapi/render-object-table" (dict "title" $caption "properties" $param_dict) }} diff --git a/layouts/partials/openapi/render-request.html b/layouts/partials/openapi/render-request.html index 3d4b0381b..96e19f693 100644 --- a/layouts/partials/openapi/render-request.html +++ b/layouts/partials/openapi/render-request.html @@ -26,10 +26,24 @@

Request

{{ if $parameters }}

Request parameters

- {{ partial "openapi/render-parameters" (dict "parameters" $parameters "type" "header" "caption" "header parameters") }} - {{ partial "openapi/render-parameters" (dict "parameters" $parameters "type" "path" "caption" "path parameters") }} - {{ partial "openapi/render-parameters" (dict "parameters" $parameters "type" "query" "caption" "query parameters") }} - + {{ partial "openapi/render-parameters" (dict + "parameters" $parameters + "type" "header" + "caption" "header parameters" + "path" $path + ) }} + {{ partial "openapi/render-parameters" (dict + "parameters" $parameters + "type" "path" + "caption" "path parameters" + "path" $path + ) }} + {{ partial "openapi/render-parameters" (dict + "parameters" $parameters + "type" "query" + "caption" "query parameters" + "path" $path + ) }} {{ end }} {{ if $request_body }} @@ -53,7 +67,7 @@

Request body

{{/* Show the content types and description. */}} - {{ $mimes := slice }} + {{ $mimes := slice }} {{ range $mime, $body := $request_body.content }} {{ $mimes = $mimes | append $mime }} {{ end }} diff --git a/layouts/partials/openapi/resolve-ref-object.html b/layouts/partials/openapi/resolve-ref-object.html new file mode 100644 index 000000000..cd3e71d4f --- /dev/null +++ b/layouts/partials/openapi/resolve-ref-object.html @@ -0,0 +1,69 @@ +{{/* + +Handles OpenAPI "Reference Objects". + +Reference objects are JSON objects with a single property, `$ref` (and +optionally a `summary` and `description`). This partial resolves the reference +and returns the expanded object. + +The input parameter is a dict with the following keys: + +* `schema`: A schema object to check for $ref properties. + +* `path`: The path of the schema file containing the (potential) ref; used for resolving + relative references. + +Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#reference-object. + +*/}} + +{{ $schema := .schema }} +{{ $path := .path }} + +{{ $ret := $schema }} + +{{ $ref_value := index $schema "$ref"}} +{{ if $ref_value }} + {{/* Resolve the ref URI relative to the path of the schema file */}} + {{ $base_uri := urls.Parse $path }} + {{ $ref_uri := urls.Parse $ref_value }} + {{ $full_uri := $base_uri.ResolveReference $ref_uri }} + + {{/* strip the extension, and the leading `/`, from the path */}} + {{ $full_path := strings.TrimPrefix "/" (replaceRE "\\.[^\\.]*$" "" $full_uri.Path) }} + + {{ $pieces := split $full_path "/" }} + {{ $ret = index site.Data $pieces }} + + {{ if $ref_uri.Fragment }} + {{/* + Per https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#relative-references-in-uris: + + > If a URI contains a fragment identifier, then the fragment should + > be resolved per the fragment resolution mechanism of the + > referenced document. If the representation of the referenced + > document is JSON or YAML, then the fragment identifier SHOULD be + > interpreted as a JSON-Pointer as per RFC6901. + + RFC6901, in a nutshell, says the pointer is a series of keys + separated by `/`. We strip off the leading `/` and use the + subsequent keys as indexes. + */}} + + {{ $keys := split (strings.TrimPrefix "/" $ref_uri.Fragment ) "/" }} + {{ $ret = index $ret $keys }} + {{ end }} + + {{/* + OpenAPI spec says that "summary" and "description" from the reference object override + the values from the referenced component. + */}} + {{ if isset $schema "summary" }} + {{ $ret = merge $ret (dict "summary" $schema.summary) }} + {{ end }} + {{ if isset $schema "description" }} + {{ $ret = merge $ret (dict "description" $schema.summary) }} + {{ end }} +{{ end }} + +{{ return $ret }}