From 564444d43edb70d77fdf1233e5f381001dbcb115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Tue, 20 Jun 2023 19:33:06 +0200 Subject: [PATCH] Render binary request and response bodies (#1579) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- assets/scss/custom.scss | 2 +- .../newsfragments/1579.clarification | 1 + data/api/client-server/account-data.yaml | 2 + data/api/client-server/content-repo.yaml | 18 +-- .../partials/openapi/render-content-type.html | 27 ++++ layouts/partials/openapi/render-request.html | 51 ++++++-- .../partials/openapi/render-responses.html | 115 ++++++++++-------- 7 files changed, 140 insertions(+), 76 deletions(-) create mode 100644 changelogs/client_server/newsfragments/1579.clarification create mode 100644 layouts/partials/openapi/render-content-type.html diff --git a/assets/scss/custom.scss b/assets/scss/custom.scss index 9d748bd2..7cdc35ce 100644 --- a/assets/scss/custom.scss +++ b/assets/scss/custom.scss @@ -374,7 +374,7 @@ footer { padding: 1rem; } - &.object-table, &.response-table { + &.object-table, &.response-table, &.content-type-table { border: 1px $table-border-color solid; caption { diff --git a/changelogs/client_server/newsfragments/1579.clarification b/changelogs/client_server/newsfragments/1579.clarification new file mode 100644 index 00000000..d53f2352 --- /dev/null +++ b/changelogs/client_server/newsfragments/1579.clarification @@ -0,0 +1 @@ +Render binary request and response bodies. diff --git a/data/api/client-server/account-data.yaml b/data/api/client-server/account-data.yaml index b4526198..bf89b21b 100644 --- a/data/api/client-server/account-data.yaml +++ b/data/api/client-server/account-data.yaml @@ -327,6 +327,8 @@ paths: `M_INVALID_PARAM`." content: application/json: + schema: + $ref: ../client-server/definitions/errors/error.yaml examples: response: value: { diff --git a/data/api/client-server/content-repo.yaml b/data/api/client-server/content-repo.yaml index 7792b2a9..c8800279 100644 --- a/data/api/client-server/content-repo.yaml +++ b/data/api/client-server/content-repo.yaml @@ -39,10 +39,7 @@ paths: requestBody: content: application/octet-stream: - schema: - type: string - example: - format: byte + example: description: The content to be uploaded. required: true responses: @@ -142,10 +139,7 @@ paths: requestBody: content: application/octet-stream: - schema: - type: string - example: - format: byte + example: description: The content to be uploaded. required: true responses: @@ -361,10 +355,8 @@ paths: content: application/octet-stream: schema: - type: string # This is a workaround for us not being able to say the response is required. description: "**Required.** The bytes for the uploaded file." - format: binary "307": description: A redirect to the thumbnail of the requested content. headers: @@ -500,10 +492,8 @@ paths: content: application/octet-stream: schema: - type: string # This is a workaround for us not being able to say the response is required. description: "**Required.** The bytes for the uploaded file." - format: binary "307": description: A redirect to the thumbnail of the requested content. headers: @@ -657,15 +647,11 @@ paths: content: image/jpeg: schema: - type: string # This is a workaround for us not being able to say the response is required. description: "**Required.** The bytes for the thumbnail." - format: binary image/png: schema: - type: string description: "**Required.** The bytes for the thumbnail." - format: binary "307": description: A redirect to the thumbnail of the requested content. headers: diff --git a/layouts/partials/openapi/render-content-type.html b/layouts/partials/openapi/render-content-type.html new file mode 100644 index 00000000..da1a69bd --- /dev/null +++ b/layouts/partials/openapi/render-content-type.html @@ -0,0 +1,27 @@ +{{/* + + Render a table showing content type and description, given: + + * `content_type`: the content type as a string + + * `description`: the description as a string + +*/}} + +{{ $content_type := .content_type }} +{{ $description := .description}} + +{{ if $content_type }} + + + + + + + + + + +
Content-TypeDescription
{{ $content_type }}{{ $description | markdownify -}}
+ +{{ end }} diff --git a/layouts/partials/openapi/render-request.html b/layouts/partials/openapi/render-request.html index 36b846da..ce31943c 100644 --- a/layouts/partials/openapi/render-request.html +++ b/layouts/partials/openapi/render-request.html @@ -35,10 +35,13 @@ {{ if $request_body }}

Request body

{{/* - A request can have several content types. Only show the schema for JSON. + A request can have several content types. */}} {{ $json_body := index $request_body.content "application/json" }} {{ if $json_body }} + {{/* + Display the JSON schemas + */}} {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $json_body.schema "path" $path) }} {{ $schema := partial "json-schema/resolve-allof" $schema }} @@ -47,6 +50,16 @@ {{ range $additional_types }} {{ partial "openapi/render-object-table" . }} {{ end }} + {{ else }} + {{/* + Show the content types and description. + */}} + {{ $mimes := slice }} + {{ range $mime, $body := $request_body.content }} + {{ $mimes = $mimes | append $mime }} + {{ end }} + {{ $content_type := delimit $mimes "|"}} + {{ partial "openapi/render-content-type" (dict "content_type" $content_type "description" $request_body.description) }} {{ end }}

Request body example

@@ -54,17 +67,41 @@ Show all the examples. */}} {{ range $mime, $body := $request_body.content }} - {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $body.schema "path" $path) }} - {{ $schema := partial "json-schema/resolve-allof" $schema }} + {{ $example := dict }} + + {{ if $body.schema }} + {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $body.schema "path" $path) }} + {{ $schema := partial "json-schema/resolve-allof" $schema }} + + {{ $example = partial "json-schema/resolve-example" $schema }} + {{ end }} - {{ $example := partial "json-schema/resolve-example" $schema }} - {{ $example_json := jsonify (dict "indent" " ") $example }} - {{ $example_json = replace $example_json "\\u003c" "<" }} - {{ $example_json = replace $example_json "\\u003e" ">" | safeHTML }} + {{ if and (eq ($example | len) 0) $body.example }} + {{/* + If no example was generated from the schema, fallback to the + main example. + */}} + {{ $example = $body.example }} + {{ end }} + {{ if eq $mime "application/json" }} + {{ $example_json := jsonify (dict "indent" " ") $example }} + {{ $example_json = replace $example_json "\\u003c" "<" }} + {{ $example_json = replace $example_json "\\u003e" ">" | safeHTML }} ```json {{ $example_json }} ``` + {{ else }} + {{ $example = $example | safeHTML }} + {{/* + We need to set a language for the code otherwise the styling + is different than other examples. + */}} +```json +{{ $example }} +``` + {{ end }} + {{ end }} {{ end }} diff --git a/layouts/partials/openapi/render-responses.html b/layouts/partials/openapi/render-responses.html index 9ef643e5..37538b6e 100644 --- a/layouts/partials/openapi/render-responses.html +++ b/layouts/partials/openapi/render-responses.html @@ -38,73 +38,84 @@ {{ range $code, $response := $responses }} - {{/* - A response can have several content types so only insert the title once. - */}} - {{ $is_title_set := false }} - {{ range $content_type, $content := $response.content }} - {{ if $content.schema }} - - {{ if not $is_title_set }} - {{ $is_title_set = true }} + {{ if $response.content }}

{{$code}} response

- {{ end }} - - {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $content.schema "path" $path) }} - {{ $schema := partial "json-schema/resolve-allof" $schema }} - {{/* - All this is to work out how to express the content of the response - in the case where it is an array. + A response can have several content types. */}} - {{ if eq $schema.type "array" }} - {{ $type_of := "" }} - {{ if $schema.items.anyOf }} - {{ $types := slice }} - {{ range $schema.items.anyOf }} - {{ if .title }} - {{ $types = $types | append .title}} - {{ else }} - {{ $types = $types | append .type }} + {{ $json_body := index $response.content "application/json" }} + {{ if $json_body }} + {{/* + Display the JSON schemas + */}} + + {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $json_body.schema "path" $path) }} + {{ $schema := partial "json-schema/resolve-allof" $schema }} + + {{/* + All this is to work out how to express the content of the response + in the case where it is an array. + */}} + {{ if eq $schema.type "array" }} + {{ $type_of := "" }} + {{ if $schema.items.anyOf }} + {{ $types := slice }} + {{ range $schema.items.anyOf }} + {{ if .title }} + {{ $types = $types | append .title}} + {{ else }} + {{ $types = $types | append .type }} + {{ end }} {{ end }} + {{ $type_of = delimit $types ", "}} + {{ else }} + {{ $type_of = $schema.items.title }} {{ end }} - {{ $type_of = delimit $types ", "}} - {{ else }} - {{ $type_of = $schema.items.title }} - {{ end }}

Array of {{ $type_of }}.

- {{ end }} + {{ end }} - {{/* - render object tables for any objects referenced in the - response. (This will be a no-op for response types which aren't - objects or arrays.) - */}} - {{ $additional_types := partial "json-schema/resolve-additional-types" (dict "schema" $schema "anchor_base" $anchor_base) }} - {{ $additional_types = uniq $additional_types }} - {{ range $additional_types }} - {{ partial "openapi/render-object-table" . }} - {{ end }} - - {{/* - render an example. currently this is only supported for arrays and objects. - */}} - {{ if or (eq $schema.type "object") (eq $schema.type "array") }} - {{ $example := partial "json-schema/resolve-example" $schema }} - {{ if $content.examples }} - {{ $example = partial "json-schema/resolve-refs" (dict "schema" $content.examples "path" $path) }} - {{ $example = $example.response.value }} + {{/* + render object tables for any objects referenced in the + response. (This will be a no-op for response types which aren't + objects or arrays.) + */}} + {{ $additional_types := partial "json-schema/resolve-additional-types" (dict "schema" $schema "anchor_base" $anchor_base) }} + {{ $additional_types = uniq $additional_types }} + {{ range $additional_types }} + {{ partial "openapi/render-object-table" . }} {{ end }} - {{ $example_json := jsonify (dict "indent" " ") $example }} - {{ $example_json = replace $example_json "\\u003c" "<" }} - {{ $example_json = replace $example_json "\\u003e" ">" | safeHTML }} + {{/* + render an example. currently this is only supported for arrays and objects. + */}} + {{ if or (eq $schema.type "object") (eq $schema.type "array") }} + {{ $example := partial "json-schema/resolve-example" $schema }} + {{ if $json_body.examples }} + {{ $example = partial "json-schema/resolve-refs" (dict "schema" $json_body.examples "path" $path) }} + {{ $example = $example.response.value }} + {{ end }} + + {{ $example_json := jsonify (dict "indent" " ") $example }} + {{ $example_json = replace $example_json "\\u003c" "<" }} + {{ $example_json = replace $example_json "\\u003e" ">" | safeHTML }} ```json {{ $example_json }} ``` {{ end }} + {{ else }} + {{/* + Show the content types and description. + */}} + {{ $mimes := slice }} + {{ $desc := "" }} + {{ range $mime, $body := $response.content }} + {{ $mimes = $mimes | append $mime }} + {{ $desc = $body.schema.description }} + {{ end }} + {{ $content_type := delimit $mimes "|"}} + {{ partial "openapi/render-content-type" (dict "content_type" $content_type "description" $desc) }} {{ end }} {{ end }} {{ end }}