Merge pull request #112 from davidebianchi/add-new-oas-fields-to-definition

This commit is contained in:
Davide Bianchi
2023-04-17 10:24:07 +02:00
committed by GitHub
7 changed files with 175 additions and 4 deletions

View File

@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- add new fields to Definition:
- Security
- Tags
- Summary
- Description
- Deprecated
- Extensions
### Updated
- update kin-openapi to 0.114.0: this change removes components from exposed oas (if not manually set). In this update of kin-openapi, there is a breaking change with the T struct, which now accepts component as pointer.

View File

@@ -37,3 +37,12 @@ func (o *Operation) AddResponse(status int, response *openapi3.Response) {
}
o.Operation.AddResponse(status, response)
}
func (o *Operation) addSecurityRequirements(securityRequirements SecurityRequirements) {
if securityRequirements != nil && o.Security == nil {
o.Security = openapi3.NewSecurityRequirements()
}
for _, securityRequirement := range securityRequirements {
o.Security.With(openapi3.SecurityRequirement(securityRequirement))
}
}

View File

@@ -71,15 +71,42 @@ type ContentValue struct {
Description string
}
type SecurityRequirements []SecurityRequirement
type SecurityRequirement map[string][]string
// Definitions of the route.
// To see how to use, refer to https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md
type Definitions struct {
// Specification extensions https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions
Extensions map[string]interface{}
// Optional field for documentation
Tags []string
Summary string
Description string
Deprecated bool
// PathParams contains the path parameters. If empty is autocompleted from the path
PathParams ParameterValue
Querystring ParameterValue
Headers ParameterValue
Cookies ParameterValue
RequestBody *ContentValue
Responses map[int]ContentValue
Security SecurityRequirements
}
func newOperationFromDefinition(schema Definitions) Operation {
operation := NewOperation()
operation.Responses = make(openapi3.Responses)
operation.Tags = schema.Tags
operation.Extensions = schema.Extensions
operation.addSecurityRequirements(schema.Security)
operation.Description = schema.Description
operation.Summary = schema.Summary
operation.Deprecated = schema.Deprecated
return operation
}
const (
@@ -91,9 +118,7 @@ const (
// AddRoute add a route with json schema inferred by passed schema.
func (r Router[HandlerFunc, Route]) AddRoute(method string, path string, handler HandlerFunc, schema Definitions) (Route, error) {
operation := NewOperation()
operation.Responses = make(openapi3.Responses)
operation.Tags = schema.Tags
operation := newOperationFromDefinition(schema)
err := r.resolveRequestBodySchema(schema.RequestBody, operation)
if err != nil {

View File

@@ -20,7 +20,6 @@ const formDataType = "multipart/form-data"
type TestRouter = Router[gorilla.HandlerFunc, gorilla.Route]
func TestAddRoutes(t *testing.T) {
type User struct {
Name string `json:"name" jsonschema:"title=The user name,required" jsonschema_extras:"example=Jane"`
PhoneNumber int `json:"phone" jsonschema:"title=mobile number of user"`
@@ -435,6 +434,66 @@ func TestAddRoutes(t *testing.T) {
testPath: "/users",
fixturesPath: "testdata/tags.json",
},
{
name: "schema with security",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Security: SecurityRequirements{
SecurityRequirement{
"api_key": []string{},
"auth": []string{
"resource.write",
},
},
},
})
require.NoError(t, err)
},
testPath: "/users",
fixturesPath: "testdata/security.json",
},
{
name: "schema with extension",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Extensions: map[string]interface{}{
"x-extension-field": map[string]string{
"foo": "bar",
},
},
})
require.NoError(t, err)
},
testPath: "/users",
fixturesPath: "testdata/extension.json",
},
{
name: "invalid extension - not starts with x-",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/", okHandler, Definitions{
Extensions: map[string]interface{}{
"extension-field": map[string]string{
"foo": "bar",
},
},
})
require.EqualError(t, err, "extra sibling fields: [extension-field]")
},
fixturesPath: "testdata/empty.json",
},
{
name: "schema with summary, description, deprecated and operationID",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Summary: "small description",
Description: "this is the long route description",
Deprecated: true,
})
require.NoError(t, err)
},
testPath: "/users",
fixturesPath: "testdata/users-deprecated-with-description.json",
},
}
for _, test := range tests {

21
testdata/extension.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"responses": {
"default": {
"description": ""
}
},
"x-extension-field": {
"foo": "bar"
}
}
}
}
}

26
testdata/security.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"responses": {
"default": {
"description": ""
}
},
"security": [
{
"api_key": [],
"auth": [
"resource.write"
]
}
]
}
}
}
}

View File

@@ -0,0 +1,21 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"deprecated": true,
"description": "this is the long route description",
"responses": {
"default": {
"description": ""
}
},
"summary": "small description"
}
}
}
}