Add logic to generate openapi response structures (#18192)
This commit is contained in:
parent
398cf38e1e
commit
a54678fb6b
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
openapi: Add logic to generate openapi response structures
|
||||
```
|
|
@ -13,6 +13,8 @@ import (
|
|||
"github.com/hashicorp/vault/sdk/logical"
|
||||
"github.com/hashicorp/vault/sdk/version"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// OpenAPI specification (OAS): https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
|
||||
|
@ -389,7 +391,7 @@ func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix st
|
|||
|
||||
// Set the final request body. Only JSON request data is supported.
|
||||
if len(s.Properties) > 0 || s.Example != nil {
|
||||
requestName := constructRequestName(requestResponsePrefix, path)
|
||||
requestName := constructRequestResponseName(path, requestResponsePrefix, "Request")
|
||||
doc.Components.Schemas[requestName] = s
|
||||
op.RequestBody = &OASRequestBody{
|
||||
Required: true,
|
||||
|
@ -469,6 +471,41 @@ func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix st
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
responseSchema := &OASSchema{
|
||||
Type: "object",
|
||||
Properties: make(map[string]*OASSchema),
|
||||
}
|
||||
|
||||
for name, field := range resp.Fields {
|
||||
openapiField := convertType(field.Type)
|
||||
p := OASSchema{
|
||||
Type: openapiField.baseType,
|
||||
Description: cleanString(field.Description),
|
||||
Format: openapiField.format,
|
||||
Pattern: openapiField.pattern,
|
||||
Enum: field.AllowedValues,
|
||||
Default: field.Default,
|
||||
Deprecated: field.Deprecated,
|
||||
DisplayAttrs: field.DisplayAttrs,
|
||||
}
|
||||
if openapiField.baseType == "array" {
|
||||
p.Items = &OASSchema{
|
||||
Type: openapiField.items,
|
||||
}
|
||||
}
|
||||
responseSchema.Properties[name] = &p
|
||||
}
|
||||
|
||||
if len(resp.Fields) != 0 {
|
||||
responseName := constructRequestResponseName(path, requestResponsePrefix, "Response")
|
||||
doc.Components.Schemas[responseName] = responseSchema
|
||||
content = OASContent{
|
||||
"application/json": &OASMediaTypeObject{
|
||||
Schema: &OASSchema{Ref: fmt.Sprintf("#/components/schemas/%s", responseName)},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
op.Responses[code] = &OASResponse{
|
||||
|
@ -493,14 +530,17 @@ func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix st
|
|||
return nil
|
||||
}
|
||||
|
||||
// constructRequestName joins the given prefix with the path elements into a
|
||||
// CamelCaseRequest string.
|
||||
// constructRequestResponseName joins the given path with prefix & suffix into
|
||||
// a CamelCase request or response name.
|
||||
//
|
||||
// For example, prefix="kv" & path=/config/lease/{name} => KvConfigLeaseRequest
|
||||
func constructRequestName(requestResponsePrefix string, path string) string {
|
||||
// For example, path=/config/lease/{name}, prefix="secret", suffix="request"
|
||||
// will result in "SecretConfigLeaseRequest"
|
||||
func constructRequestResponseName(path, prefix, suffix string) string {
|
||||
var b strings.Builder
|
||||
|
||||
b.WriteString(strings.Title(requestResponsePrefix))
|
||||
title := cases.Title(language.English)
|
||||
|
||||
b.WriteString(title.String(prefix))
|
||||
|
||||
// split the path by / _ - separators
|
||||
for _, token := range strings.FieldsFunc(path, func(r rune) bool {
|
||||
|
@ -508,11 +548,11 @@ func constructRequestName(requestResponsePrefix string, path string) string {
|
|||
}) {
|
||||
// exclude request fields
|
||||
if !strings.ContainsAny(token, "{}") {
|
||||
b.WriteString(strings.Title(token))
|
||||
b.WriteString(title.String(token))
|
||||
}
|
||||
}
|
||||
|
||||
b.WriteString("Request")
|
||||
b.WriteString(suffix)
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
|
|
@ -477,6 +477,16 @@ func TestOpenAPI_Paths(t *testing.T) {
|
|||
"amount": 42,
|
||||
},
|
||||
},
|
||||
Fields: map[string]*FieldSchema{
|
||||
"field_a": {
|
||||
Type: TypeString,
|
||||
Description: "field_a description",
|
||||
},
|
||||
"field_b": {
|
||||
Type: TypeBool,
|
||||
Description: "field_b description",
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -229,9 +229,10 @@ type RequestExample struct {
|
|||
|
||||
// Response describes and optional demonstrations an operation response.
|
||||
type Response struct {
|
||||
Description string // summary of the the response and should always be provided
|
||||
MediaType string // media type of the response, defaulting to "application/json" if empty
|
||||
Example *logical.Response // example response data
|
||||
Description string // summary of the the response and should always be provided
|
||||
MediaType string // media type of the response, defaulting to "application/json" if empty
|
||||
Fields map[string]*FieldSchema // the fields present in this response, used to generate openapi response
|
||||
Example *logical.Response // example response data
|
||||
}
|
||||
|
||||
// PathOperation is a concrete implementation of OperationHandler.
|
||||
|
|
|
@ -34,11 +34,7 @@
|
|||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"example": {
|
||||
"data": {
|
||||
"amount": 42
|
||||
}
|
||||
}
|
||||
"$ref": "#/components/schemas/KvFooResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +45,19 @@
|
|||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"KvFooResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"field_a": {
|
||||
"type": "string",
|
||||
"description": "field_a description"
|
||||
},
|
||||
"field_b": {
|
||||
"type": "boolean",
|
||||
"description": "field_b description"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ require (
|
|||
github.com/stretchr/testify v1.7.0
|
||||
go.uber.org/atomic v1.9.0
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||
golang.org/x/text v0.3.3
|
||||
google.golang.org/grpc v1.41.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
)
|
||||
|
@ -59,7 +60,6 @@ require (
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue