Distinguish LIST-only paths in OpenAPI (#13643)

* Distinguish LIST-only paths in OpenAPI

* add changelog

* Put enum field inside schema
This commit is contained in:
VAL 2022-01-18 09:21:44 -08:00 committed by GitHub
parent daefbd0a54
commit 6652203569
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 3 deletions

3
changelog/13643.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
sdk: Fixes OpenAPI to distinguish between paths that can do only List, or both List and Read.
```

View File

@ -368,8 +368,18 @@ func documentPath(p *Path, specialPaths *logical.Paths, backendType logical.Back
} }
} }
// LIST is represented as GET with a `list` query parameter // LIST is represented as GET with a `list` query parameter.
if opType == logical.ListOperation || (opType == logical.ReadOperation && operations[logical.ListOperation] != nil) { if opType == logical.ListOperation {
// Only accepts List (due to the above skipping of ListOperations that also have ReadOperations)
op.Parameters = append(op.Parameters, OASParameter{
Name: "list",
Description: "Must be set to `true`",
Required: true,
In: "query",
Schema: &OASSchema{Type: "string", Enum: []interface{}{"true"}},
})
} else if opType == logical.ReadOperation && operations[logical.ListOperation] != nil {
// Accepts both Read and List
op.Parameters = append(op.Parameters, OASParameter{ op.Parameters = append(op.Parameters, OASParameter{
Name: "list", Name: "list",
Description: "Return a list if `true`", Description: "Return a list if `true`",

View File

@ -320,7 +320,7 @@ func TestOpenAPI_Paths(t *testing.T) {
testPath(t, p, sp, expected("legacy")) testPath(t, p, sp, expected("legacy"))
}) })
t.Run("Operations", func(t *testing.T) { t.Run("Operations - All Operations", func(t *testing.T) {
p := &Path{ p := &Path{
Pattern: "foo/" + GenericNameRegex("id"), Pattern: "foo/" + GenericNameRegex("id"),
Fields: map[string]*FieldSchema{ Fields: map[string]*FieldSchema{
@ -395,6 +395,65 @@ func TestOpenAPI_Paths(t *testing.T) {
testPath(t, p, sp, expected("operations")) testPath(t, p, sp, expected("operations"))
}) })
t.Run("Operations - List Only", func(t *testing.T) {
p := &Path{
Pattern: "foo/" + GenericNameRegex("id"),
Fields: map[string]*FieldSchema{
"id": {
Type: TypeString,
Description: "id path parameter",
},
"flavors": {
Type: TypeCommaStringSlice,
Description: "the flavors",
},
"name": {
Type: TypeNameString,
Default: "Larry",
Description: "the name",
},
"age": {
Type: TypeInt,
Description: "the age",
AllowedValues: []interface{}{1, 2, 3},
Required: true,
DisplayAttrs: &DisplayAttributes{
Name: "Age",
Sensitive: true,
Group: "Some Group",
Value: 7,
},
},
"x-abc-token": {
Type: TypeHeader,
Description: "a header value",
AllowedValues: []interface{}{"a", "b", "c"},
},
"format": {
Type: TypeString,
Description: "a query param",
Query: true,
},
},
HelpSynopsis: "Synopsis",
HelpDescription: "Description",
Operations: map[logical.Operation]OperationHandler{
logical.ListOperation: &PathOperation{
Summary: "List Summary",
Description: "List Description",
},
},
DisplayAttrs: &DisplayAttributes{
Navigation: true,
},
}
sp := &logical.Paths{
Root: []string{"foo*"},
}
testPath(t, p, sp, expected("operations_list"))
})
t.Run("Responses", func(t *testing.T) { t.Run("Responses", func(t *testing.T) {
p := &Path{ p := &Path{
Pattern: "foo", Pattern: "foo",

View File

@ -0,0 +1,63 @@
{
"openapi": "3.0.2",
"info": {
"title": "HashiCorp Vault API",
"description": "HTTP API that gives you full access to Vault. All API routes are prefixed with `/v1/`.",
"version": "<vault_version>",
"license": {
"name": "Mozilla Public License 2.0",
"url": "https://www.mozilla.org/en-US/MPL/2.0"
}
},
"paths": {
"/foo/{id}": {
"description": "Synopsis",
"x-vault-sudo": true,
"x-vault-displayAttrs": {
"navigation": true
},
"parameters": [
{
"name": "format",
"description": "a query param",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "id",
"description": "id path parameter",
"in": "path",
"schema": {
"type": "string"
},
"required": true
}
],
"get": {
"operationId": "getFooId",
"tags": ["secrets"],
"summary": "List Summary",
"description": "List Description",
"responses": {
"200": {
"description": "OK"
}
},
"parameters": [
{
"name": "list",
"description": "Must be set to `true`",
"required": true,
"in": "query",
"schema": {
"type": "string",
"enum": ["true"]
}
}
]
}
}
}
}