Introduce experimental OpenAPI shortcode
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Tic Tac Toe",
|
||||
"description": "This API allows writing down marks on a Tic Tac Toe board\nand requesting the state of the board or of individual squares.\n",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "Gameplay"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/board": {
|
||||
"get": {
|
||||
"summary": "Get the whole board",
|
||||
"description": "Retrieves the current state of the board and the winner.",
|
||||
"tags": ["Gameplay"],
|
||||
"operationId": "get-board",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/status"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"defaultApiKey": []
|
||||
},
|
||||
{
|
||||
"app2AppOauth": ["board:read"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/board/{row}/{column}": {
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/components/parameters/rowParam"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/columnParam"
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"summary": "Get a single board square",
|
||||
"description": "Retrieves the requested square.",
|
||||
"tags": ["Gameplay"],
|
||||
"operationId": "get-square",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/mark"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The provided parameters are incorrect",
|
||||
"content": {
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/errorMessage"
|
||||
},
|
||||
"example": "Illegal coordinates"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerHttpAuthentication": []
|
||||
},
|
||||
{
|
||||
"user2AppOauth": ["board:read"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"summary": "Set a single board square",
|
||||
"description": "Places a mark on the board and retrieves the whole board and the winner (if any).",
|
||||
"tags": ["Gameplay"],
|
||||
"operationId": "put-square",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/mark"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/status"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The provided parameters are incorrect",
|
||||
"content": {
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/errorMessage"
|
||||
},
|
||||
"examples": {
|
||||
"illegalCoordinates": {
|
||||
"value": "Illegal coordinates."
|
||||
},
|
||||
"notEmpty": {
|
||||
"value": "Square is not empty."
|
||||
},
|
||||
"invalidMark": {
|
||||
"value": "Invalid Mark (X or O)."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerHttpAuthentication": []
|
||||
},
|
||||
{
|
||||
"user2AppOauth": ["board:write"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"parameters": {
|
||||
"rowParam": {
|
||||
"description": "Board row (vertical coordinate)",
|
||||
"name": "row",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/coordinate"
|
||||
}
|
||||
},
|
||||
"columnParam": {
|
||||
"description": "Board column (horizontal coordinate)",
|
||||
"name": "column",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/coordinate"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"errorMessage": {
|
||||
"type": "string",
|
||||
"maxLength": 256,
|
||||
"description": "A text message describing an error"
|
||||
},
|
||||
"coordinate": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 3,
|
||||
"example": 1
|
||||
},
|
||||
"mark": {
|
||||
"type": "string",
|
||||
"enum": [".", "X", "O"],
|
||||
"description": "Possible values for a board square. `.` means empty square.",
|
||||
"example": "."
|
||||
},
|
||||
"board": {
|
||||
"type": "array",
|
||||
"maxItems": 3,
|
||||
"minItems": 3,
|
||||
"items": {
|
||||
"type": "array",
|
||||
"maxItems": 3,
|
||||
"minItems": 3,
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/mark"
|
||||
}
|
||||
}
|
||||
},
|
||||
"winner": {
|
||||
"type": "string",
|
||||
"enum": [".", "X", "O"],
|
||||
"description": "Winner of the game. `.` means nobody has won yet.",
|
||||
"example": "."
|
||||
},
|
||||
"status": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"winner": {
|
||||
"$ref": "#/components/schemas/winner"
|
||||
},
|
||||
"board": {
|
||||
"$ref": "#/components/schemas/board"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securitySchemes": {
|
||||
"defaultApiKey": {
|
||||
"description": "API key provided in console",
|
||||
"type": "apiKey",
|
||||
"name": "api-key",
|
||||
"in": "header"
|
||||
},
|
||||
"basicHttpAuthentication": {
|
||||
"description": "Basic HTTP Authentication",
|
||||
"type": "http",
|
||||
"scheme": "Basic"
|
||||
},
|
||||
"bearerHttpAuthentication": {
|
||||
"description": "Bearer token using a JWT",
|
||||
"type": "http",
|
||||
"scheme": "Bearer",
|
||||
"bearerFormat": "JWT"
|
||||
},
|
||||
"app2AppOauth": {
|
||||
"type": "oauth2",
|
||||
"flows": {
|
||||
"clientCredentials": {
|
||||
"tokenUrl": "https://learn.openapis.org/oauth/2.0/token",
|
||||
"scopes": {
|
||||
"board:read": "Read the board"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"user2AppOauth": {
|
||||
"type": "oauth2",
|
||||
"flows": {
|
||||
"authorizationCode": {
|
||||
"authorizationUrl": "https://learn.openapis.org/oauth/2.0/auth",
|
||||
"tokenUrl": "https://learn.openapis.org/oauth/2.0/token",
|
||||
"scopes": {
|
||||
"board:read": "Read the board",
|
||||
"board:write": "Write to the board"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,62 +5,42 @@ layout: landing
|
||||
<br />
|
||||
|
||||
# Hugo Book {anchor=false}
|
||||
{{% columns %}}
|
||||
- Documentation theme for [Hugo](https://gohugo.io) as simple as plain book.
|
||||
|
||||
Documentation theme for [Hugo](https://gohugo.io) as simple as plain book.
|
||||
|
||||
Hugo-Book theme is designed to be easy to read, write, navigate and maintain.
|
||||
It is an attempt to create a sustainable web project.
|
||||
|
||||
{{<button href="/docs/getting-started/introduction">}}Explore{{</button>}}
|
||||
|
||||
- ```shell
|
||||
# TL;DR
|
||||
git clone https://github.com/alex-shpak/hugo-book-starter documentation
|
||||
cd documentation
|
||||
git submodule update --init --remote
|
||||
hugo server --minify
|
||||
```
|
||||
{{% /columns %}}
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
{{% columns %}}
|
||||
- {{< card >}}
|
||||
### Probably fast {anchor=false}
|
||||
- ### Probably fast {anchor=false}
|
||||
Built on Hugo static site generator. "The world’s fastest framework for building websites".
|
||||
{{< /card >}}
|
||||
|
||||
- {{< card >}}
|
||||
### 50% JS free {anchor=false}
|
||||
- ### 50% JS free {anchor=false}
|
||||
All important features are working even with JavaScript disabled in the browser, including interactive shortcodes.
|
||||
{{< /card >}}
|
||||
|
||||
- {{< card >}}
|
||||
### Minimalistic {anchor=false}
|
||||
- ### Minimalistic {anchor=false}
|
||||
For real, it is very minimalistic, black on white. No extra tools are needed to build the site, only Hugo. No heavy JS or CSS frameworks included.
|
||||
{{< /card >}}
|
||||
{{% /columns %}}
|
||||
|
||||
{{% columns %}}
|
||||
- {{< card >}}
|
||||
### Shortcodes {anchor=false}
|
||||
- ### Shortcodes {anchor=false}
|
||||
Pretty good shortcodes are included to enhance content:
|
||||
[Columns](/docs/content/shortcodes/columns/),
|
||||
[Cards](/docs/content/shortcodes/cards/),
|
||||
[Cards](/docs/content/shortcodes/experimental/cards/),
|
||||
[Tabs](/docs/content/shortcodes/tabs/),
|
||||
[Images](/docs/content/shortcodes/images/),
|
||||
[Images](/docs/content/shortcodes/experimental/images/),
|
||||
[Asciinema](/docs/content/shortcodes/asciinema/),
|
||||
[KaTex](/docs/content/shortcodes/katex/),
|
||||
[Mermaid](/docs/content/shortcodes/mermaid/) and others.
|
||||
{{< /card >}}
|
||||
|
||||
- {{< card >}}
|
||||
### Even more {anchor=false}
|
||||
- ### Even more {anchor=false}
|
||||
Do people actually read these? I thought it was just a visual filler. But there is full-text search and multi-language support.
|
||||
{{< /card >}}
|
||||
|
||||
- {{< card >}}
|
||||
### Made to be extendable {anchor=false}
|
||||
- ### Made to be extendable {anchor=false}
|
||||
There are multiple points to inject own styles and templates to make it your own.
|
||||
{{< /card >}}
|
||||
{{% /columns %}}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
bookCollapseSection: true
|
||||
---
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# Cards
|
||||
|
||||
Content blocks with optional images and links. Often used with [Columns](/docs/content/shortcodes/columns) for grid layouts.
|
||||
Content blocks with optional images and links. Often used with [Columns](/docs/content/shortcodes/columns/) for grid layouts.
|
||||
|
||||
## Syntax
|
||||
|
||||
@@ -18,7 +18,7 @@ Markdown content
|
||||
Cards can display an image above the content.
|
||||
{{< /card >}}
|
||||
|
||||
- {{< card href="/docs/content/shortcodes/cards" >}}
|
||||
- {{< card href="/docs/content/shortcodes/experimental/cards/" >}}
|
||||
### With Link {anchor=false}
|
||||
When `href` is set, the entire card becomes clickable.
|
||||
{{< /card >}}
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: OpenAPI
|
||||
---
|
||||
|
||||
# OpenAPI
|
||||
|
||||
Renders an OpenAPI 3.x specification as a documentation page. Operations are grouped by their first tag.
|
||||
|
||||
## Syntax
|
||||
|
||||
```tpl
|
||||
{{%/* openapi src="spec.json" */%}}
|
||||
```
|
||||
|
||||
The spec file is loaded via `resources.Get`, so the path is relative to the site's `assets/` directory. JSON and YAML are both supported.
|
||||
|
||||
## Example
|
||||
|
||||
{{% openapi src="tictactoe.json" %}}
|
||||
@@ -0,0 +1,385 @@
|
||||
{{- $source := or (.Get "src") (.Get 0) -}}
|
||||
{{- with resources.Get $source -}}
|
||||
{{- $raw := . -}}
|
||||
{{- if or (strings.HasSuffix $source ".yaml") (strings.HasSuffix $source ".yml") -}}
|
||||
{{- $raw = resources.FromString (printf "%s.json" $source) (. | transform.Unmarshal | jsonify) -}}
|
||||
{{- end -}}
|
||||
{{- $spec := openapi3.Unmarshal $raw -}}
|
||||
|
||||
{{ with $spec.Info }}{{ template "openapi-info" (dict "info" . "externalDocs" $spec.ExternalDocs) }}{{ end }}
|
||||
{{ with $spec.Servers }}{{ template "openapi-servers" (dict "servers" .) }}{{ end }}
|
||||
{{ with $spec.Components }}{{ with .SecuritySchemes }}{{ template "openapi-security" (dict "schemes" .) }}{{ end }}{{ end }}
|
||||
{{ template "openapi-operations" (dict "spec" $spec) }}
|
||||
{{ with $spec.Components }}{{ with .Schemas }}{{ template "openapi-models" (dict "schemas" .) }}{{ end }}{{ end }}
|
||||
|
||||
{{- else -}}
|
||||
{{- errorf "openapi shortcode: resource %q not found" $source -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Info ========== */ -}}
|
||||
{{- define "openapi-info" -}}
|
||||
{{- $info := .info -}}
|
||||
{{- $externalDocs := .externalDocs }}
|
||||
{{ with $info.Description }}{{ . }}{{ end }}
|
||||
|
||||
{{ $meta := slice -}}
|
||||
{{- with $info.Version }}{{ $meta = $meta | append (printf "`v%s`" .) }}{{ end -}}
|
||||
{{- with $info.License }}{{ if .URL }}{{ $meta = $meta | append (printf "[%s](%s)" .Name .URL) }}{{ else }}{{ $meta = $meta | append .Name }}{{ end }}{{ end -}}
|
||||
{{- with $info.Contact }}{{ with .Email }}{{ $meta = $meta | append (printf "[%s](mailto:%s)" . .) }}{{ end }}{{ end -}}
|
||||
{{- with $info.TermsOfService }}{{ $meta = $meta | append (printf "[Terms of service](%s)" .) }}{{ end -}}
|
||||
{{- with $externalDocs }}{{ $meta = $meta | append (printf "[%s](%s)" (or .Description .URL) .URL) }}{{ end }}
|
||||
|
||||
{{ delimit $meta " \n" | safeHTML }}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Servers ========== */ -}}
|
||||
{{- define "openapi-servers" }}
|
||||
|
||||
## Servers
|
||||
|
||||
{{ range .servers }}
|
||||
{{ with .Description }}{{ . | chomp | replaceRE "\n" " " }}{{ else }}Server{{ end }}
|
||||
: [`{{ .URL }}`]({{ .URL }})
|
||||
{{- range $name, $var := .Variables }}
|
||||
: `{{ $name }}`: default `{{ $var.Default }}`{{ with $var.Enum }}, enum: {{ delimit . ", " }}{{ end }}{{ with $var.Description }}, {{ . | chomp | replaceRE "\n" " " }}{{ end }}
|
||||
{{- end }}
|
||||
{{ end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Security ========== */ -}}
|
||||
{{- define "openapi-security" -}}
|
||||
{{- $schemes := .schemes }}
|
||||
|
||||
## Security
|
||||
|
||||
{{ range $name, $schemeRef := $schemes }}
|
||||
{{- with $schemeRef.Value }}
|
||||
{{ with .Description }}{{ . | chomp | replaceRE "\n" " " }}
|
||||
: `{{ $name }}`
|
||||
{{ else }}`{{ $name }}`
|
||||
{{ end -}}
|
||||
: `{{ .Type }}`{{ with .Scheme }} `{{ . }}`{{ end }}{{ with .In }} in `{{ . }}`{{ end }}{{ with .Name }} (`{{ . }}`){{ end }}{{ with .BearerFormat }} `{{ . }}`{{ end }}{{ with .OpenIdConnectUrl }}, discovery: [{{ . }}]({{ . }}){{ end }}
|
||||
{{- end }}
|
||||
{{ end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Operations (grouped by tag) ========== */ -}}
|
||||
{{- define "openapi-operations" -}}
|
||||
{{- $spec := .spec -}}
|
||||
{{- $methods := slice "GET" "POST" "PUT" "PATCH" "DELETE" "HEAD" "OPTIONS" "TRACE" -}}
|
||||
{{- $locations := slice
|
||||
(dict "in" "path" "label" "Path parameters")
|
||||
(dict "in" "query" "label" "Query parameters")
|
||||
(dict "in" "header" "label" "Header parameters")
|
||||
(dict "in" "cookie" "label" "Cookie parameters") -}}
|
||||
|
||||
{{- /* Bucket each operation under every tag it declares */ -}}
|
||||
{{- $byTag := dict -}}
|
||||
{{- range $path, $pathItem := $spec.Paths.Map -}}
|
||||
{{- range $method := $methods -}}
|
||||
{{- with index $pathItem.Operations $method -}}
|
||||
{{- $tags := .Tags -}}
|
||||
{{- if not $tags }}{{ $tags = slice "API" }}{{ end -}}
|
||||
{{- $entry := dict "path" $path "method" $method "operation" . "pathItem" $pathItem -}}
|
||||
{{- range $tag := $tags -}}
|
||||
{{- $bucket := index $byTag $tag | default slice -}}
|
||||
{{- $byTag = merge $byTag (dict $tag ($bucket | append $entry)) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{ range $tag, $entries := $byTag }}
|
||||
|
||||
## {{ $tag | title }}
|
||||
|
||||
{{ range $entry := $entries }}
|
||||
{{ template "openapi-operation" (dict "spec" $spec "path" $entry.path "method" $entry.method "operation" $entry.operation "pathItem" $entry.pathItem "locations" $locations) }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Operation ========== */ -}}
|
||||
{{- define "openapi-operation" -}}
|
||||
{{- $spec := .spec -}}
|
||||
{{- $path := .path -}}
|
||||
{{- $method := .method -}}
|
||||
{{- $operation := .operation -}}
|
||||
{{- $pathItem := .pathItem -}}
|
||||
{{- $locations := .locations }}
|
||||
|
||||
{{- $title := or $operation.Summary (printf "`%s %s`" (upper $method) $path) -}}
|
||||
{{- if $operation.Deprecated }}{{ $title = printf "~~%s~~" $title }}{{ end }}
|
||||
|
||||
### {{ $title }}{{ with $operation.OperationID }} {id="op-{{ anchorize . }}"}{{ end }}
|
||||
|
||||
{{ with $operation.Description }}{{ . }}
|
||||
|
||||
{{ end -}}
|
||||
{{- with $operation.ExternalDocs }}[{{ with .Description }}{{ . | chomp | replaceRE "\n" " " }}{{ else }}{{ .URL }}{{ end }}]({{ .URL }})
|
||||
|
||||
{{ end -}}
|
||||
|
||||
{{- $security := $operation.Security -}}
|
||||
{{- if not $security }}{{ $security = $spec.Security }}{{ end }}
|
||||
|
||||
{{ $requirementStrings := slice -}}
|
||||
{{- range $requirement := $security -}}
|
||||
{{- $schemeLinks := slice -}}
|
||||
{{- range $schemeName, $_ := $requirement -}}
|
||||
{{- $schemeLinks = $schemeLinks | append (printf "[%s](#security)" $schemeName) -}}
|
||||
{{- end -}}
|
||||
{{- if $schemeLinks }}{{ $requirementStrings = $requirementStrings | append (delimit $schemeLinks " and ") }}{{ end -}}
|
||||
{{- end }}
|
||||
|
||||
#### Request{{ if $requirementStrings }} (requires {{ delimit $requirementStrings ", " }}){{ end }}
|
||||
|
||||
```tpl
|
||||
{{ upper $method }} {{ $path }}
|
||||
```
|
||||
|
||||
|
||||
{{- /* Dedup: operation-level overrides path-level by name+in */ -}}
|
||||
{{- $opKeys := dict -}}
|
||||
{{- range $operation.Parameters }}{{ with .Value }}{{ $opKeys = merge $opKeys (dict (printf "%s:%s" .In .Name) true) }}{{ end }}{{ end -}}
|
||||
{{- $allParams := slice -}}
|
||||
{{- range $pp := $pathItem.Parameters }}{{ with $pp.Value }}{{ if not (isset $opKeys (printf "%s:%s" .In .Name)) }}{{ $allParams = $allParams | append $pp }}{{ end }}{{ end }}{{ end -}}
|
||||
{{- $allParams = append $allParams $operation.Parameters -}}
|
||||
{{ template "openapi-parameters" (dict "allParams" $allParams "locations" $locations) }}
|
||||
{{- with $operation.RequestBody }}{{ with .Value -}}
|
||||
{{ template "openapi-request-body" (dict "requestBody" .) }}
|
||||
{{- end }}{{ end }}
|
||||
{{- with $operation.Responses -}}
|
||||
{{ template "openapi-responses" (dict "responses" .) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Parameters ========== */ -}}
|
||||
{{- define "openapi-parameters" -}}
|
||||
{{- $allParams := .allParams -}}
|
||||
{{- range .locations -}}
|
||||
{{- $location := .in -}}
|
||||
{{- $params := slice -}}
|
||||
{{- range $allParams -}}
|
||||
{{- with .Value }}{{ if eq .In $location }}{{ $params = $params | append . }}{{ end }}{{ end -}}
|
||||
{{- end }}
|
||||
{{- if $params }}
|
||||
|
||||
#### {{ .label }}
|
||||
|
||||
| Parameter name | Value | Description | Additional |
|
||||
|----------------|-------|-------------|------------|
|
||||
{{- range $params }}
|
||||
| `{{ .Name }}` | {{ with .Schema }}{{ template "openapi-type" . }}{{ end }} | {{ with .Description }}{{ . | chomp | replaceRE "\n" " " }}{{ end }} | {{ template "openapi-param-extras" . }} |
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "openapi-param-extras" -}}
|
||||
{{- $bits := slice -}}
|
||||
{{- if .Required }}{{ $bits = $bits | append "Required" }}{{ end -}}
|
||||
{{- if .Deprecated }}{{ $bits = $bits | append "Deprecated" }}{{ end -}}
|
||||
{{- $example := .Example -}}
|
||||
{{- $default := "" -}}
|
||||
{{- with .Schema }}{{ with .Value -}}
|
||||
{{- with .Default }}{{ $default = . }}{{ end -}}
|
||||
{{- if not $example }}{{ with .Example }}{{ $example = . }}{{ end }}{{ end -}}
|
||||
{{- end }}{{ end -}}
|
||||
{{- with $default }}{{ $bits = $bits | append (printf "Default: `%v`" .) }}{{ end -}}
|
||||
{{- with $example }}{{ $bits = $bits | append (printf "Example: `%v`" .) }}{{ end -}}
|
||||
{{- delimit $bits ", " -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Request body ========== */ -}}
|
||||
{{- define "openapi-request-body" -}}
|
||||
{{- with .requestBody -}}
|
||||
{{- if or .Description .Content }}
|
||||
|
||||
#### Request body{{ if .Required }} (required){{ end }}
|
||||
|
||||
{{ with .Description }}{{ . }}{{ end }}
|
||||
{{ range $mediaType, $obj := .Content }}
|
||||
{{ template "openapi-media-examples" (dict "mediaType" $mediaType "examples" $obj.Examples "example" $obj.Example) }}
|
||||
{{- end -}}
|
||||
{{ template "openapi-schema-summary" (dict "content" .Content) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Responses ========== */ -}}
|
||||
{{- define "openapi-responses" -}}
|
||||
{{- $responses := .responses -}}
|
||||
{{- with $responses }}
|
||||
|
||||
#### Responses
|
||||
|
||||
{{ range $code, $codeRef := .Map -}}
|
||||
{{- with $codeRef.Value }}
|
||||
`{{ $code }}`{{ with .Description }}: {{ . | chomp | replaceRE "\n" " " }}{{ end }}
|
||||
{{ with .Content }}{{ range $mediaType, $obj := . }}
|
||||
{{ template "openapi-media-examples" (dict "mediaType" $mediaType "examples" $obj.Examples "example" $obj.Example) }}
|
||||
{{- end -}}
|
||||
{{ template "openapi-schema-summary" (dict "content" .) }}
|
||||
{{ end -}}
|
||||
{{ template "openapi-headers-detail" (dict "code" $code "headers" .Headers) }}
|
||||
{{- end }}
|
||||
{{ end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "openapi-headers-detail" -}}
|
||||
{{- $code := .code -}}
|
||||
{{- with .headers }}
|
||||
|
||||
`{{ $code }}` response headers:
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
{{- range $name, $hdrRef := . }}
|
||||
{{- with $hdrRef.Value }}
|
||||
| `{{ $name }}` | {{ with .Schema }}{{ template "openapi-type" . }}{{ end }} | {{ with .Description }}{{ . | chomp | replaceRE "\n" " " }}{{ end }} |
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Media examples (author-provided only) ========== */ -}}
|
||||
{{- define "openapi-media-examples" -}}
|
||||
{{- $mediaType := .mediaType -}}
|
||||
{{- $examples := .examples -}}
|
||||
{{- $example := .example -}}
|
||||
{{- if $examples -}}
|
||||
{{- range $name, $exRef := $examples }}
|
||||
{{- with $exRef.Value }}
|
||||
|
||||
{{ with .Summary }}{{ . }}{{ else }}{{ $name }}{{ end }}{{ with .Description }} - {{ . | chomp | replaceRE "\n" " " }}{{ end }}
|
||||
```jsonc {filename="{{ $mediaType }}"}
|
||||
{{ jsonify (dict "indent" " ") .Value | safeHTML }}
|
||||
```
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- else if $example }}
|
||||
```jsonc {filename="{{ $mediaType }}"}
|
||||
{{ jsonify (dict "indent" " ") $example | safeHTML }}
|
||||
```
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Schema summary (type caption + embedded properties table) ========== */ -}}
|
||||
{{- define "openapi-schema-summary" -}}
|
||||
{{- $schemaRef := "" -}}
|
||||
{{- range $mt, $obj := .content -}}
|
||||
{{- if not $schemaRef }}{{ with $obj.Schema }}{{ $schemaRef = . }}{{ end }}{{ end -}}
|
||||
{{- end -}}
|
||||
{{- with $schemaRef }}
|
||||
Schema: {{ template "openapi-type" . }}
|
||||
{{- /* Unwrap arrays so `array of Pet` embeds the Pet table */ -}}
|
||||
{{- $value := $schemaRef.Value -}}
|
||||
{{- $itemRef := $schemaRef -}}
|
||||
{{- if and $value (not $value.Properties) $value.Items -}}
|
||||
{{- $itemRef = $value.Items -}}
|
||||
{{- end -}}
|
||||
{{- with $itemRef.Value -}}
|
||||
{{- if or .Properties .AllOf }}
|
||||
|
||||
{{ template "openapi-properties-table" (dict "schema" $itemRef) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Models ========== */ -}}
|
||||
{{- define "openapi-models" -}}
|
||||
{{- $schemas := .schemas }}
|
||||
|
||||
## Models
|
||||
|
||||
{{ range $name, $schemaRef := $schemas -}}
|
||||
{{- with $schemaRef.Value }}
|
||||
|
||||
### {{ $name }} {id="model-{{ $name | anchorize }}"}
|
||||
|
||||
{{ with .Description }}{{ . | chomp }}
|
||||
|
||||
{{ end -}}
|
||||
{{- $parents := slice -}}
|
||||
{{- range .AllOf }}{{ if .Ref }}{{ $parents = $parents | append . }}{{ end }}{{ end -}}
|
||||
{{- with $parents }}Inherits from {{ range $i, $p := . }}{{ if $i }}, {{ end }}{{ template "openapi-schema-link" $p }}{{ end }}.
|
||||
|
||||
{{ end -}}
|
||||
{{- if or .Properties .AllOf -}}
|
||||
{{ template "openapi-properties-table" (dict "schema" $schemaRef) }}
|
||||
{{- else -}}
|
||||
Type: {{ template "openapi-type" $schemaRef }}{{ with .Enum }} (enum: {{ range $i, $v := . }}{{ if $i }}, {{ end }}`{{ $v }}`{{ end }}){{ end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{ end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Properties table ========== */ -}}
|
||||
{{- define "openapi-properties-table" -}}
|
||||
{{- $schemaRef := .schema -}}
|
||||
{{- with $schemaRef.Value -}}
|
||||
{{- $props := dict -}}
|
||||
{{- $required := slice -}}
|
||||
{{- with .Properties }}{{ $props = merge $props . }}{{ end -}}
|
||||
{{- with .Required }}{{ $required = $required | append . }}{{ end -}}
|
||||
{{- range .AllOf -}}
|
||||
{{- if not .Ref -}}
|
||||
{{- with .Value -}}
|
||||
{{- with .Properties }}{{ $props = merge $props . }}{{ end -}}
|
||||
{{- with .Required }}{{ $required = $required | append . }}{{ end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if $props }}
|
||||
|
||||
| Property | Type | Required | Description |
|
||||
|----------|------|----------|-------------|
|
||||
{{- range $name, $prop := $props -}}
|
||||
{{- $isRequired := in $required $name }}
|
||||
| `{{ $name }}` | {{ template "openapi-type" $prop }} | {{ if $isRequired }}yes{{ else }}no{{ end }} | {{ with $prop.Value.Description }}{{ . | chomp | replaceRE "\n" " " }}{{ end }} |
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- /* ========== Type cell (handles ref, array, primitive) ========== */ -}}
|
||||
{{- define "openapi-type" -}}
|
||||
{{- if .Ref -}}
|
||||
{{- template "openapi-schema-link" . -}}
|
||||
{{- else -}}
|
||||
{{- with .Value -}}
|
||||
{{- $t := "" -}}{{- with .Type }}{{ with .Slice }}{{ $t = index . 0 }}{{ end }}{{ end -}}
|
||||
{{- if eq $t "array" -}}
|
||||
array of {{ template "openapi-type" .Items }}
|
||||
{{- else if $t -}}
|
||||
{{ $t }}{{ with .Format }} ({{ . }}){{ end }}
|
||||
{{- else if .Enum -}}
|
||||
enum
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /* ========== Schema link (#model-name) ========== */ -}}
|
||||
{{- define "openapi-schema-link" -}}
|
||||
{{- $parts := split .Ref "/" -}}
|
||||
{{- $name := index $parts (sub (len $parts) 1) -}}
|
||||
[{{ $name }}](#model-{{ $name | anchorize }})
|
||||
{{- end -}}
|
||||
Reference in New Issue
Block a user