From 477023b0fb8dc0b1c9a2f0d87484c80b7fa59f7f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 13 Mar 2024 13:40:56 +0000 Subject: [PATCH 1/3] Add a new `partial` for resolving object refs, properly --- .../partials/json-schema/resolve-refs.html | 8 ++ .../partials/openapi/resolve-ref-object.html | 74 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 layouts/partials/openapi/resolve-ref-object.html 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/resolve-ref-object.html b/layouts/partials/openapi/resolve-ref-object.html new file mode 100644 index 000000000..0041d688d --- /dev/null +++ b/layouts/partials/openapi/resolve-ref-object.html @@ -0,0 +1,74 @@ +{{/* + +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. + +* `root_schema`: The top-level schema which contains the potential ref; use for resolving `#/` + references. + +Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#reference-object. + +*/}} + +{{ $schema := .schema }} +{{ $path := .path }} +{{ $root_schema := .root_schema }} + +{{ $ret := $schema }} + +{{ $ref_value := index $schema "$ref"}} +{{ if $ref_value }} + {{ $ref_url := urls.Parse $ref_value }} + + {{ if ne $ref_url.Path "" }} + {{/* Reference to a different file: load it */}} + {{ $full_path := path.Join $path $ref_url.Path }} + {{ $without_ext := replaceRE "\\.[^\\.]*$" "" $full_path }} + {{ $pieces := split $without_ext "/" }} + {{ $ret = index site.Data $pieces }} + {{ else }} + {{ $ret = $root_schema }} + {{ end }} + + {{ if ne $ref_url.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_url.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 }} From cc978c5ab51979ae791f229e610b1297d19e1e64 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 13 Mar 2024 13:47:49 +0000 Subject: [PATCH 2/3] Resolve reference objects in parameters This requires us to pass down $root_schema and $path. --- layouts/partials/openapi/render-api.html | 2 +- .../partials/openapi/render-operation.html | 4 ++- .../partials/openapi/render-parameters.html | 36 ++++++++++++------- layouts/partials/openapi/render-request.html | 30 +++++++++++++--- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/layouts/partials/openapi/render-api.html b/layouts/partials/openapi/render-api.html index 8af18e970..541fe10d8 100644 --- a/layouts/partials/openapi/render-api.html +++ b/layouts/partials/openapi/render-api.html @@ -21,7 +21,7 @@ {{/* note that a `paths` entry can be a $ref */}} - {{ $params := dict "endpoint" $endpoint "path" $path }} + {{ $params := dict "endpoint" $endpoint "path" $path "root_schema" $api_data }} {{ with $path_data.get }} diff --git a/layouts/partials/openapi/render-operation.html b/layouts/partials/openapi/render-operation.html index 253e2efe8..3d5a472d9 100644 --- a/layouts/partials/openapi/render-operation.html +++ b/layouts/partials/openapi/render-operation.html @@ -6,6 +6,7 @@ * `endpoint`: the endpoint * `operation_data`: the OpenAPI data for the operation * `path`: the path where this definition was found, to enable us to resolve "$ref" + * `root_schema`: the root schema object where this definition was found, to enable us to resolve local "$ref" references This template renders the operation as a `
` containing: @@ -22,6 +23,7 @@ {{ $endpoint := .endpoint }} {{ $operation_data := .operation_data }} {{ $path := .path }} +{{ $root_schema := .root_schema }} {{ $anchor := anchorize $endpoint }}
@@ -80,7 +82,7 @@


-{{ partial "openapi/render-request" (dict "parameters" $operation_data.parameters "request_body" $operation_data.requestBody "path" $path "anchor_base" $anchor ) }} +{{ partial "openapi/render-request" (dict "parameters" $operation_data.parameters "request_body" $operation_data.requestBody "path" $path "anchor_base" $anchor "root_schema" $root_schema ) }}
{{ partial "openapi/render-responses" (dict "responses" $operation_data.responses "path" $path "anchor_base" $anchor ) }} diff --git a/layouts/partials/openapi/render-parameters.html b/layouts/partials/openapi/render-parameters.html index 925b01979..e874d86bd 100644 --- a/layouts/partials/openapi/render-parameters.html +++ b/layouts/partials/openapi/render-parameters.html @@ -3,8 +3,10 @@ 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" + * `root_schema`: the root schema object where this definition was found, to enable us to resolve local "$ref" references This template renders a single table containing parameters of the given type. @@ -13,14 +15,23 @@ {{ $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 := . }} +{{ $root_schema := .root_schema }} +{{ $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 + "root_schema" $root_schema + "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 +40,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..24b09d5e4 100644 --- a/layouts/partials/openapi/render-request.html +++ b/layouts/partials/openapi/render-request.html @@ -5,6 +5,7 @@ * `parameters`: OpenAPI data specifying the parameters * `request_body`: OpenAPI data specifying the request body * `path`: the path where this definition was found, to enable us to resolve "$ref" + * `root_schema`: the root schema object where this definition was found, to enable us to resolve local "$ref" references * `anchor_base`: a prefix to add to the HTML anchors generated for each object This template renders: @@ -17,6 +18,7 @@ {{ $parameters := .parameters }} {{ $request_body := .request_body }} {{ $path := .path }} +{{ $root_schema := .root_schema }} {{ $anchor_base := .anchor_base }}

Request

@@ -26,10 +28,28 @@

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 + "root_schema" $root_schema + ) }} + {{ partial "openapi/render-parameters" (dict + "parameters" $parameters + "type" "path" + "caption" "path parameters" + "path" $path + "root_schema" $root_schema + ) }} + {{ partial "openapi/render-parameters" (dict + "parameters" $parameters + "type" "query" + "caption" "query parameters" + "root_schema" $root_schema + "path" $path + "root_schema" $root_schema + ) }} {{ end }} {{ if $request_body }} @@ -53,7 +73,7 @@

Request body

{{/* Show the content types and description. */}} - {{ $mimes := slice }} + {{ $mimes := slice }} {{ range $mime, $body := $request_body.content }} {{ $mimes = $mimes | append $mime }} {{ end }} From 44db1640194f4f7b2ea78dfa6e376c85e88fe8d2 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 13 Mar 2024 13:49:58 +0000 Subject: [PATCH 3/3] changelog --- changelogs/internal/newsfragments/1749.clarification | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/internal/newsfragments/1749.clarification 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.