Skip to content

Commit

Permalink
Add a new partial for resolving object refs, properly
Browse files Browse the repository at this point in the history
  • Loading branch information
richvdh committed Mar 13, 2024
1 parent 9068c33 commit 013b33a
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
8 changes: 8 additions & 0 deletions layouts/partials/json-schema/resolve-refs.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
75 changes: 75 additions & 0 deletions layouts/partials/openapi/resolve-ref-object.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{{/*

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-reference s-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 }}
{{ warnf "Ref val %s keys %s ret %s" $ref_value $keys $ret }}
{{ 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 }}

0 comments on commit 013b33a

Please sign in to comment.