getkin / kin-openapi Goto Github PK
View Code? Open in Web Editor NEWOpenAPI 3.0 (and Swagger v2) implementation for Go (parsing, converting, validation, and more)
License: MIT License
OpenAPI 3.0 (and Swagger v2) implementation for Go (parsing, converting, validation, and more)
License: MIT License
$ go get -v github.com/jban332/kin-openapi/openapi3
github.com/jban332/kin-openapi/jsoninfo
# github.com/jban332/kin-openapi/jsoninfo
../../jban332/kin-openapi/jsoninfo/marshal.go:158:36: typeInfo.Extensions undefined (type *TypeInfo has no field or method Extensions)
../../jban332/kin-openapi/jsoninfo/unmarshal.go:125:36: typeInfo.Extensions undefined (type *TypeInfo has no field or method Extensions)```
Hi,
What is the reasoning or explanation behind the difference here
https://godoc.org/github.com/getkin/kin-openapi/openapi3#Swagger
vs
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#openapi-object
The inconsistency/deviation I am referring to is that in the official docs path
is required but in the implementation in this library it is not required.
There are other inconsistencies but this one is the main one - other examples include:
query param with anyOf failed to parse
Openapi yaml with:
paths:
/resource-store:
get:
operationId: SearchResources
tags:
components:
schemas:
RESOURCEType:
anyOf:
====
when I succeeded to build and run the server, it panics at requests with this message:
echo: http: panic serving [::1]:56426: schema has non primitive type ""
goroutine 12 [running]:
net/http.(*conn).serve.func1(0xc000088140)
/usr/local/go/src/net/http/server.go:1769 +0x139
panic(0x86c960, 0xc0004740a0)
/usr/local/go/src/runtime/panic.go:522 +0x1b5
github.com/getkin/kin-openapi/openapi3filter.parsePrimitive(0xc00002c6e0, 0x3, 0xc00022cd00, 0x23, 0xc00005b7b8, 0x3, 0x3)
/home/admin/go/src/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go:705 +0xa1e
github.com/getkin/kin-openapi/openapi3filter.(*urlValuesDecoder).DecodePrimitive(0xc000010040, 0xc000161fe0, 0xd, 0xc000466080, 0xc00022cd00, 0x8, 0xc000010040, 0x5, 0x0)
/home/admin/go/src/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go:412 +0x329
github.com/getkin/kin-openapi/openapi3filter.decodeValue(0x9c6ba0, 0xc000010040, 0xc000161fe0, 0xd, 0xc000466080, 0xc00022cd00, 0x0, 0x0, 0x0, 0x0)
/home/admin/go/src/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go:243 +0xcf
github.com/getkin/kin-openapi/openapi3filter.decodeStyledParameter(0xc0000e0500, 0xc00045c450, 0x0, 0x0, 0x0, 0x0)
/home/admin/go/src/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go:225 +0x134
github.com/getkin/kin-openapi/openapi3filter.ValidateParameter(0x9c7f20, 0xc00045c4b0, 0xc00045c450, 0xc0000e0500, 0x0, 0x0)
/home/admin/go/src/github.com/getkin/kin-openapi/openapi3filter/validate_request.go:95 +0x350
github.com/getkin/kin-openapi/openapi3filter.ValidateRequest(0x9c7f20, 0xc00045c4b0, 0xc00045c450, 0x9b4cf0, 0x9117e0)
/home/admin/go/src/github.com/getkin/kin-openapi/openapi3filter/validate_request.go:49 +0x243
github.com/deepmap/oapi-codegen/pkg/middleware.ValidateRequestFromContext(0x9d4600, 0xc0000de5a0, 0xc000142b60, 0x0, 0x5d259d4c, 0xb0915dc)
/home/admin/go/src/github.com/deepmap/oapi-codegen/pkg/middleware/oapi_validate.go:115 +0x537
github.com/deepmap/oapi-codegen/pkg/middleware.OapiRequestValidatorWithOptions.func1.1(0x9d4600, 0xc0000de5a0, 0xd09620, 0xc00005bc28)
/home/admin/go/src/github.com/deepmap/oapi-codegen/pkg/middleware/oapi_validate.go:69 +0x54
github.com/labstack/echo/middleware.LoggerWithConfig.func2.1(0x9d4600, 0xc0000de5a0, 0x2, 0x2)
/home/admin/go/src/github.com/labstack/echo/middleware/logger.go:119 +0x1c0
github.com/labstack/echo.(*Echo).ServeHTTP(0xc000224380, 0x9c6fa0, 0xc0000c6000, 0xc0000e8000)
/home/admin/go/src/github.com/labstack/echo/echo.go:616 +0x22d
net/http.serverHandler.ServeHTTP(0xc00014a9c0, 0x9c6fa0, 0xc0000c6000, 0xc0000e8000)
/usr/local/go/src/net/http/server.go:2774 +0xa8
net/http.(*conn).serve(0xc000088140, 0x9c7e60, 0xc000458840)
The request is:
curl "localhost:8080/resource-store?resource-type=CPU"
I solved the issue by simply declaring:
RESOURCEType:
type: string
Still, I'd like to understand the cause behind the former syntax and the possibility to get the former syntax work.
Thanks,
Charlie
I was using this library to do some request and response validation and noticed that when I pass in a string to a respnse property when it should be a number or integer the validation still passes.
Here is my example openapi that has a 200 response returning a variable "badguy" that should be an integer:
{
"openapi": "3.0.0",
"info": {
"title": "Verify stuff fails",
"version": "1.0.0"
},
"paths": {
"/badguy": {
"get": {
"summary": "Get the bad guy",
"description": "get the bad guy",
"responses": {
"200": {
"description": "blarg",
"content": {
"application/json": {
"schema": {
"properties": {
"badguy": {
"type": "integer",
"description": "using this to force a failure to test validation works",
"example": 123
}
}
}
}
}
}
}
}
}
}
}
And then using the example from this projects readme:
func TestUnitNumberShouldFailIfStringIsReturned(t *testing.T) {
router := openapi3filter.NewRouter().WithSwaggerFromFile("../min.json")
ctx := context.TODO()
httpReq, _ := http.NewRequest(http.MethodGet, "/badguy", nil)
// Find route
route, pathParams, _ := router.FindRoute(httpReq.Method, httpReq.URL)
// Validate request
requestValidationInput := &openapi3filter.RequestValidationInput{
Request: httpReq,
PathParams: pathParams,
Route: route,
}
if err := openapi3filter.ValidateRequest(ctx, requestValidationInput); err != nil {
panic(err)
}
var (
respStatus = 200
respContentType = "application/json"
respBody = bytes.NewBufferString(`{"badguy":"blarg"}`)
)
log.Println("Response:", respStatus)
responseValidationInput := &openapi3filter.ResponseValidationInput{
RequestValidationInput: requestValidationInput,
Status: respStatus,
Header: http.Header{
"Content-Type": []string{
respContentType,
},
},
}
if respBody != nil {
data, _ := json.Marshal(respBody)
responseValidationInput.SetBodyBytes(data)
}
// Validate response.
if err := openapi3filter.ValidateResponse(ctx, responseValidationInput); err != nil {
panic(err)
}
}
I return {"badguy":"blarg"} as the response body to validate. When running the validation, it passes. I expected it to fail. Is this an incorrect expectation for this library?
Edit: Added a branch with the test added to it to make debugging easier: https://github.com/tateexon/kin-openapi/tree/verify_response_parameter_type_test
How decode with this library the struct ExtensionProps
?
I succeeded to read: swagger.ExtensionProps.Extensions["x-XXXXXXX"]
but the output is a json.RawMessage
type = []byte
.
Should I use the JSON libraries to decode or we can use a functionality of the library ?
My code:
package main
import (
"fmt"
"log"
"github.com/getkin/kin-openapi/openapi3"
)
func main() {
loader := openapi3.NewSwaggerLoader()
[...]
swagger, err := loader.LoadSwaggerFromData(data)
if err != nil {
log.Fatal("error", err)
}
fmt.Println(string(swagger.Extensions["x-XXXXXXX"].(json.RawMessage)))
}
Is it possible to create an example for decoding this structure ?
Thank you !
This is an issue I've encountered while using ApiSprout. According to the spec, bearerFormat
is an arbitrary string that specifies how the bearer token is formatted
as seen here: https://swagger.io/docs/specification/authentication/bearer-authentication/.
On the other hand, it seems like kin-openapi
only accepts JWT
or an empty string for this field:
kin-openapi/openapi3/security_scheme.go
Line 124 in 2557c53
I'm not much of a Go afficionado, but it seems like that whole switch statement can be removed, as we don't need to do any validation on this value.
Hey,
We use a custom format with type "number" e.g.:
"eo:epsg": {
"type": "number",
"format": "epsg-code",
...
}
There is the function DefineStringFormat implemented into openapi3 (related issues #103, #79), but it only handles elements with type "string". So there is a need for a DefineNumberFormat function.
According to the specification, Link
should have an OperationRef
field. It's not a blocker, because currently this data is available in the ExtensionProps
field.
As reported in danielgtaylor/apisprout#30, when given a request schema with a required readOnly
property the request validator mistakenly treats it as required. According to the spec:
readOnly boolean
Relevant only for Schema "properties" definitions. Declares the property as "read only". This means that it MAY be sent as part of a response but SHOULD NOT be sent as part of the request. If the property is marked as readOnly being true and is in the required list, the required will take effect on the response only. A property MUST NOT be marked as both readOnly and writeOnly being true. Default value is false.
Basically this means that request & response can share a schema but will see different properties as required for validation purposes.
After conversion, the resulting v3 structure's type refs are still in the form "#/definitions/" instead of "#/components/schemas/".
go.mod: github.com/getkin/kin-openapi v0.1.0
OpenAPI v3 defines additionalProperties
attribute as
Value can be boolean or object. Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. Consistent with JSON Schema, additionalProperties defaults to true.
additionalProperties: false
is not taken into account when validating JSON - a payload with attributes that are not listed in schema will still be valid.
It only happens when additionalProperties
is declared inside anyOf / allOf block
package main
import (
"encoding/json"
"fmt"
"github.com/getkin/kin-openapi/openapi3"
)
func main() {
payload := map[string]interface{}{
"prop1": "val",
"prop3": "val",
}
schemas := []string{`
{
"type": "object",
"additionalProperties": false,
"required": ["prop1"],
"properties": {
"prop1": {
"type": "string"
}
}
}`, `{
"anyOf": [
{
"type": "object",
"additionalProperties": false,
"required": ["prop1"],
"properties": {
"prop1": {
"type": "string"
}
}
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"prop2": {
"type": "string"
}
}
}
],
}
`}
for _, jsonSchema := range schemas {
var dataSchema openapi3.Schema
json.Unmarshal([]byte(jsonSchema), &dataSchema)
err := dataSchema.VisitJSON(payload)
fmt.Println("err", err)
}
}
In the openapi3 package, TestLoadFromRemoteURL can panic because it calls createTestServer with an address of localhost:3000
and that assumes that that address is not in use by the current system.
It should listen on localhost:0
instead and use an appropriate URL with the actual port number in.
When using the router, the following definition is matched properly (the corresponding route is found):
paths:
'/books/{id}':
parameters:
- schema:
type: integer
name: id
in: path
required: true
get:
# ...
But this doesn't:
paths:
parameters:
- schema:
type: integer
name: id
in: path
required: true
'/books/{id}.json':
get:
# ...
Given schema
anyOf:
- type: object
properties:
prop1:
type: string
enum:
- Dingo
- Husky
- type: object
properties:
prop2:
type: string
payload
{
"prop1": "val"
}
will pass validation, although should fail.
Also noticed, same payload will fail against
type: object
required:
- prop1
properties:
prop1:
type: string
enum:
- Dingo
- Husky
In the README is stated that openapi2
package supports
OpenAPI 2 files, including serialization, deserialization, and validation
But I can't find a way to read a swagger v2 file.
I need to convert a swagger v2 file to swagger v3. Is that possible in any way with kin-openapi
?
Is it possible to perform validation just on the contents of the request against the schema defined in the openapi definition?
I do not want to validate the path and server. The definition does has servers listed in it, but I want to ignore that.
Hello...Is it possible somehow to get a schema with refs in on go? Currently using something like this swagger.Components.Schemas["ResponseTest"]
returns {"data":{"items":{"$ref":"#/components/schemas/TestItem"},"meta":{"$ref":"#/components/schemas/ResponseMeta"},"type":"array"},"description":""}
. Ideally I would like to get the full schema instead of the ref
OpenAPI v3 support $ref
s to links and callbacks. swagger_loader doesn't have logic for handling those references.
What is the motivation for creating this project for openAPI 3.0 rather than extending either swaggo or swagger to include it?
It would be helpful to newcomers to explain this on the front page.
Hello,
From OAS3 spec:
Formats such as "email", "uuid", and so on, MAY be used even though undefined by this specification.
I was wondering if the validation can be extended to support some reasonably common formats like email
, uuid
?
Hello.
At the moment package github.com/getkin/kin-openapi/openapi3filter
support validation of parameters with type string
only.
Do you plan to add support for validation of parameters with other types?
P.S. I can help with it if you don't mind.
If I specify a empty map for oauth2 scopes, for example:
components:
securitySchemes:
auth:
type: oauth2
flows:
password:
tokenUrl: /auth/oauth2/beta1/token
scopes: {}
than I got an error when call validate:
Error when validating Components: Security scheme 'flow' is invalid: An OAuth flow is missing 'scopes'
but I should not.
Hey,
I have the following setup:
Input OpenAPI snipped:
"url": {
"type": "string",
"description": "URL to a web page with more details about the plan.",
"format": "url",
"example": "http://cool-cloud-corp.com/plans/free-plan"
}
I then load swagger by file and create a filter router with the following lines:
openapi3.DefineStringFormat("url", REGEX)
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile(ct.apifile)
router := openapi3filter.NewRouter().WithSwagger(swagger)
The last line causes the following error:
panic: Validating Swagger failed: Unsupported 'format' value 'url'
Even though I added it to the string formats in the first line, am I doing something wrong?
Is there a solution to this? (the problem seems similar to #79)
The field name of the securitySchema flow
is incorrect. Correctly is flows
.
diff --git a/openapi3/security_scheme.go b/openapi3/security_scheme.go
index b427855..75615cf 100644
--- a/openapi3/security_scheme.go
+++ b/openapi3/security_scheme.go
@@ -17,7 +17,7 @@ type SecurityScheme struct {
In string `json:"in,omitempty"`
Scheme string `json:"scheme,omitempty"`
BearerFormat string `json:"bearerFormat,omitempty"`
- Flow *OAuthFlows `json:"flow,omitempty"`
+ Flow *OAuthFlows `json:"flows,omitempty"`
}
func NewSecurityScheme() *SecurityScheme {
ref. https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject
Together with the property name of the struct is also I think it is better to fix, this struct is not worried what to do because of the public to the outside.
Should I just modify the JSON tag without changing the property name?
Historical background: The package jsoninfo
was created with the goal of having elegant serialization.
The fact that jsoninfo
resides in this repository is just a historical accident. The code is just an internal implementation detail to this project. So I created github.com/getkin/happyjson and refactored it a bit.
If there are no objections, I'll replace jsoninfo
with the external package happyjson
. Any feedback about how kin-openapi implements serialization internally is welcome.
By OpenAPI 3.0.0 specification Paths Object path have description - "The field name MUST begin with a slash".
openapi: "3.0"
info:
version: "1.0"
title: sample
basePath: /adc/v1
paths:
foo/bar:
get:
responses:
200:
description: description
/foo/{var}/:
get:
responses:
200:
description: description
This spec parses fine and return path 'foo/bar' but doesn't
Hi,
I'm dinning in OpenAPIv3 spec and just figured out that Header object fields should be the same as in Parameter.
Header Object
The Header Object follows the structure of the Parameter Object with the following changes:
name MUST NOT be specified, it is given in the corresponding headers map.
in MUST NOT be specified, it is implicitly in header.
All traits that are affected by the location MUST be applicable to a location of header (for example, style).
Hey, I would like to be able to look up an operation by method and URL, then confirm a real response body (instance of data) conforms to one of the response bodies defined on the OpenAPI v3.0 operation. Is this possible with your package ?
The following program fails with the error:
Error while unmarshalling property 'components' (*openapi3.Components): Error while unmarshalling property 'schemas' (*map[string]*openapi3.SchemaRef): Error while unmarshalling property 'discriminator' (*openapi3.Discriminator): Error while unmarshalling property 'mapping' (*map[string]*openapi3.SchemaRef): Failed to unmarshal extension properties: json: cannot unmarshal string into Go value of type map[string]json.RawMessage
Input: "#/components/schemas/Cat"
The data is a schema simplified from the the OpenAPI specification - the mappings property should be map[string]string
, or at least allow string values when unmarshaling.
package main
import (
"fmt"
"github.com/getkin/kin-openapi/openapi3"
)
var data = `
{
"openapi": "3.0.0",
"components": {
"schemas": {
"MyResponseType": {
"discriminator": {
"mapping": {
"cat": "#/components/schemas/Cat",
"dog": "#/components/schemas/Dog"
},
"propertyName": "pet_type"
},
"oneOf": [
{
"$ref": "#/components/schemas/Cat"
},
{
"$ref": "#/components/schemas/Dog"
}
]
}
}
}
}
`
func main() {
loader := openapi3.NewSwaggerLoader()
_, err := loader.LoadSwaggerFromData([]byte(data))
if err != nil {
fmt.Println("error: ", err)
} else {
fmt.Println("ok")
}
}
Hello.
According to the OpenAPI 3 specification an operation's parameter can contain keyword "explode" (see sections Describing parameters and Parameter serialization).
Do you plan to add support for the keyword?
The example under Validating HTTP requests/responses references structs that do not exist.
When validating a value against an allOf schema the validator will do them one by one and if the value validates against all schemas, it passes. However, if additonalProperties: false is set on one of the refs in allOf, then a valid object will fail if it has properties which is defined in one of the other refs, but not the one with additionalProperties: false.
I don't believe this is according to spec.
I've created a test for this which might explain this better:
{
Title: "ALL OF - additionalProperties: false",
Schema: &openapi3.Schema{
AllOf: []*openapi3.SchemaRef{
{
Value: &openapi3.Schema{
Type: "object",
AdditionalPropertiesAllowed: openapi3.BoolPtr(false),
Properties: map[string]*openapi3.SchemaRef{
"pet_type": {
Value: &openapi3.Schema{
Type: "string",
},
},
},
},
},
{
Value: &openapi3.Schema{
Type: "object",
AdditionalPropertiesAllowed: openapi3.BoolPtr(false),
Properties: map[string]*openapi3.SchemaRef{
"bark": {
Value: &openapi3.Schema{
Type: "boolean",
},
},
"breed": {
Value: &openapi3.Schema{
Type: "string",
},
},
},
},
},
},
},
Serialization: map[string]interface{}{
"allOf": []interface{}{
map[string]interface{}{
"type": "object",
"additionalProperties": false,
"properties": map[string]interface{}{
"pet_type": map[string]interface{}{
"type": "string",
},
},
},
map[string]interface{}{
"type": "object",
"additionalProperties": false,
"properties": map[string]interface{}{
"bark": map[string]interface{}{
"type": "boolean",
},
"breed": map[string]interface{}{
"type": "string",
},
},
},
},
},
AllValid: []interface{}{
map[string]interface{}{
"pet_type": "Dog",
"bark": true,
"breed": "Dingo",
},
},
AllInvalid: []interface{}{
map[string]interface{}{
"pet_type": "Dog",
"pet_name": "Charlie",
},
},
},
I'm unsure how this should be solved so I haven't created an MR for this. I think the only way to solve this properly is to resolve the allOf into a schema by merging the refs.
[email protected] failed on email validation (request body)
Error message:
Error at "/email":JSON string doesn't match the format 'email (regular expression ^[^@]+@[^@<>",\w]+$
)'
Below regex will fix it
^[^@]+@[^@<>",\\w]+$
Hello. Thank you for the great OAPI processor. Really cool stuff!
Could you please advise me a a most convenient way to json-marshal the expanded spec from Swagger struct. Something like https://goswagger.io/usage/expand.html.
As I see, SwaggerLoader resolves all $ref's (and doing it well). But I don't see an easy way to extract an expanded spec out of struct.
This seems strange, is it a mistake?
https://github.com/jban332/kin-openapi/blob/master/openapi3/schema.go#L66
BTW the readme says
openapi3.NewSwaggerLoader().LoadFromFile
while it should read
openapi3.NewSwaggerLoader().LoadSwaggerFromFile
Currently, if there are two yaml files, say petstore1.yaml and petstore2.yaml.
In petstore1.yaml, we defined schema Cat. In petstore2.yaml, we defined schema Dog.
But in petstore1.yaml, we have external reference to Dog which defined in petstore2.yaml, and in petstore2.yaml, we have external reference to Cat which defined in petstore1.yaml.
When we load the petstore1.yaml, the openapi3.loader(), it enters tight loop between:
https://github.com/getkin/kin-openapi/blob/master/openapi3/swagger_loader.go#L190
and https://github.com/getkin/kin-openapi/blob/master/openapi3/swagger_loader.go#L519
Due to that, we can not add circular detection in up layer because the initial loading of yaml does not return.
Any suggestion for fixing or workaround this?
after cloning the repo, i ran go test ./...
and saw a build error of: "url.URL literal evaluated but not used"
Discriminator property is not taken into account when validating request body.
Given example schema from https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/
request body
{
"pet_type": "Cat",
"breed": "Dingo",
"bark": true,
}
should not be valid, however it passes ValidateRequest.
Code to reproduce:
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
)
const testSchema = `openapi: 3.0.0
info:
title: ''
version: 0.0.1
paths:
/:
post:
requestBody:
required: true
content:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: pet_type
components:
schemas:
Pet:
type: object
required:
- pet_type
properties:
pet_type:
type: string
discriminator:
propertyName: pet_type
Dog:
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
breed:
type: string
enum: [Dingo, Husky, Retriever, Shepherd]
Cat:
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
hunts:
type: boolean
age:
type: integer
`
func main() {
payload := map[string]interface{}{
"pet_type": "Cat",
"breed": "Dingo",
"bark": true,
}
p, _ := json.Marshal(payload)
swagger, _ := openapi3.NewSwaggerLoader().LoadSwaggerFromData([]byte(testSchema))
router := openapi3filter.NewRouter().WithSwagger(swagger)
req, _ := http.NewRequest(http.MethodPost, "/", bytes.NewReader(p))
route, pathParams, _ := router.FindRoute(req.Method, req.URL)
req.Header.Set("Content-Type", "application/json")
requestValidationInput := &openapi3filter.RequestValidationInput{
Request: req,
PathParams: pathParams,
Route: route,
}
err := openapi3filter.ValidateRequest(context.TODO(), requestValidationInput)
if err == nil {
fmt.Println("Valid")
} else {
fmt.Println("NOT valid")
}
}
Hello!
There is an operation in my OpenAPI specification that contains a required body. I call openapi3filter.ValidateRequest
with HTTP request that does not contains a body. I expect that the function will return an error but it returns nil
.
package main
import (
"fmt"
"net/http"
"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
)
func main() {
requestBody := openapi3.NewRequestBody().
WithRequired(true).
WithJSONSchema(openapi3.NewStringSchema())
operation := openapi3.NewOperation()
operation.OperationID = "test"
operation.RequestBody = &openapi3.RequestBodyRef{Value: requestBody}
spec.AddOperation("/test", http.MethodPost, operation)
router := openapi3filter.NewRouter()
if err := router.AddSwagger(spec); err != nil {
return nil, err
}
req, err := http.NewRequest(http.Method, "/test", nil)
if err != nil {
return nil, err
}
route, pathParams, err := router.FindRoute(req.Method, req.URL)
if err != nil {
return
}
input := &openapi3filter.RequestValidationInput{Request: req, PathParams: pathParams, Route: route}
if err := openapi3filter.ValidateRequest(req.Context(), input); err != nil {
fmt.Printf("error %[1]T: %s\n", err)
return
}
fmt.Println("no error")
}
Function openapi3filter.ValidateRequest
returns nil
.
Function openapi3filter.ValidateRequest
returns *openapi3filter.RequestError
.
kin-openapi version: commit 9acc5e9.
Hey, I'm trying to parse an OpenAPI yaml/json file into a different format, I've got everything set up and it works great -- except the non-determinism with go's map. I'm not too familiar with go or OpenAPI yet but is there a better way of accomplishing this other than replacing basically every map in the library with an ordered map?
If I have a yaml file that looks like this:
openapi: 3.0.0
components:
schemas:
A:
type: "object"
B:
type: "object"
properties:
a:
$ref: '#/components/schemas/A'
I want to loop through all schemas, and ALWAYS get A then B.
Currently I'm looping like the validate methods do:
for k, v := range components.Schemas {
}
Hello, I'm not sure if this is a bug strictly-speaking, but we found it to be unexpected behavior.
Say you have a basic spec like this:
openapi: "3.0.0"
info:
title: Simple API Example
version: 0.1.0
servers:
- url: "https://example.com/api/"
description: Deployed absolute URL
- url: "http://localhost:8080/"
description: Running locally
paths:
/:
get:
summary: Application health-check.
responses:
200:
description: Application name and version.
content:
application/json:
schema:
properties:
data:
type: object
properties:
name:
type: string
example: "Sample App"
version:
type: string
example: "0.1.0"
And then a simple web app that includes validation using kin-openapi/openapi3filter
:
package main
import (
"context"
"flag"
"fmt"
"io"
"log"
"net/http"
"path/filepath"
"github.com/getkin/kin-openapi/openapi3filter"
)
func main() {
// OpenAPIv3 request validation:
specPath, _ := filepath.Abs("./spec.yaml")
oa3router := openapi3filter.NewRouter().WithSwaggerFromFile(specPath)
validationHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.TODO()
log.Printf("request.URL is %s", r.URL)
route, pathParams, _ := oa3router.FindRoute(r.Method, r.URL)
// Validate request
requestValidationInput := &openapi3filter.RequestValidationInput{
Request: r,
PathParams: pathParams,
Route: route,
}
if err := openapi3filter.ValidateRequest(ctx, requestValidationInput); err != nil {
w.WriteHeader(400)
io.WriteString(w, err.Error()+"\n")
} else {
fmt.Fprint(w, "{\"version\": \"0.1.0\", \"name\": \"Sample App\"}\n")
}
})
httpAddr := flag.String("http.addr", ":8080", "HTTP listen address")
log.Printf("HTTP server starting on %v\n", *httpAddr)
log.Fatal(http.ListenAndServe(*httpAddr, validationHandler))
}
If you run $ go run main.go
and make a request using $ curl localhost:8080
you'll find you get an invalid route
response.
The logging output is:
2019/09/27 14:24:17 HTTP server starting on :8080
2019/09/27 14:24:21 request.URL is /
As far as I can tell the issue is the same one described in this StackOverflow thread
what you get from Go's http.Request.URL is the raw URL (as parsed by the library). In the case you're getting, you're accessing the URL from a relative path, hence the lack of a Host or Scheme in the URL object.
Since the request is made from the same machine, it's only passing a relative URL, and openapi-kin
doesn't know how to validate that request successfully. Even explicitly passing a Host
header doesn't help:
$ curl localhost:8080/api -H 'Host: example.com'
invalid route
Maybe the FindRoute()
method should take into account Host
headers? Or maybe there's someplace that URL.ResolveReference()
should be called and it's not?
I'm willing to work on putting together a PR, if there's consensus for what a good fix would look like. Otherwise, I'd just ask for extra documentation that kin-openapi
validation doesn't work properly on localhost
.
Thanks for your work on a very useful tool.
Why does not it support nested all/one/anyOf?
If it is nested, the processing in visitSetOperations becomes fast = true
and an error occurs.
https://github.com/getkin/kin-openapi/blob/master/openapi3/schema.go#L698-L700
Please tell me the intention of this fast
parameter.
As noted in apisprout#1 it looks like some references can fail to parse. For example:
{
"$ref": "#/paths/~1v1~1servers/get/responses/200/content/application~1json/schema/properties/meta"
}
will fail to parse but is valid according to the spec. Rather than referencing a predefined component it is reusing a piece of another response schema. Ideally the parser would handle these cases regardless of what the link starts with.
Hello, I have a small issue with messages describing cause of invalid json documents. Perhaps I'm using it a wrong way. Here is a snippet:
package main
import (
"fmt"
"github.com/getkin/kin-openapi/openapi3"
)
func main() {
jsonschema := `
{
"type": "object",
"properties": {
"sessionId": {
"type": "string"
}
},
"required": [
"sessionId"
]
}`
schema := openapi3.NewSchema()
schema.UnmarshalJSON([]byte(jsonschema))
testjson := func(s string) {
var doc interface{}
json.Unmarshal([]byte(s), &doc)
fmt.Print(schema.VisitJSON(doc))
}
// Prints: Property 'sessionId' is missing
testjson(`{}`)
// Prints: Error at "/sessionId":Field must be set to number, integer or not be present
testjson(`{"sessionId": 50}`)
// Prints: Error at "/sessionId":Field must be set to array or not be present
testjson(`{"sessionId": []}`)
}
The last two messages tell me what actually is in the json document, not what is required to be there according to json schema.
So I would expect message like: 'Error at "/sessionId": Field must be set to string'.
This is what I have in the 3.0 YAML:
ClusterProvisionSpec:
type: object
description: Represents a configuration spec for a new cluster in an sddc.
properties:
instance_type_configs:
type: object
description: List of instances available for the new cluster.
additionalProperties:
type: array
items:
$ref: '#/definitions/InstanceTypeConfigForCluster'
"type: array" is returning as "type: object" in additionalProperties and "items" is returning as nil.
I was expecting to resolve this as Map<string, Array<InstanceTypeConfigForCluster>>
Instead, I am getting: Map<string, object>
Can you confirm if this is a bug?
if i defined following openapi , when i validator it ,will failed !
in: query
name: coordinates
content:
application/json:
schema:
type: object
required:
- lat
- long
properties:
lat:
type: number
long:
type:
i think this part need to follow "resolveRequestBodyRef" function . add
for _, contentType := range value.Content {
for name, example := range contentType.Examples {
if err := swaggerLoader.resolveExampleRef(swagger, example, path); err != nil {
return err
}
contentType.Examples[name] = example
}
if schema := contentType.Schema; schema != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, schema, path); err != nil {
return err
}
}
}
in resolveParameterRef function !
Are you using Benthos with this ?
The OpenAPI documentation (https://swagger.io/docs/specification/describing-request-body/) describes the content-type keys under requestBody.content
as supporting wildcards:
content allows wildcard media types. For example, image/* represents all image types; */* represents all types and is functionally equivalent to application/octet-stream. Specific media types have preference over wildcard media types when interpreting the spec, for example, image/png > image/* > */*
However, the current request validation only supports a direct match of content types via a map lookup. Additionally, the request validation rejects any request without a content-type header which should otherwise be handled by a */*
if defined.
My team has a specialized case where this causes validation errors because we need to support a requestor that doesn't add the content-type header. I'm happy to put up a PR that helps with this but thought I might get some feedback on the approach first:
The current lookup is handled here with a map[string]*MediaType lookup by key. However, the requestBody.Content
type has a Get
method for resolving the type that also incorporates the behavior of parseMediaType
which is used here before the map lookup. I'm guessing the Get
method was added after the initial implementation of the request validation and that the parsing and map lookup in the validation is a hold-over.
I believe we can hide the complexity of the lookup behavior in the Content.Get
method. If that approach sounds acceptable then I'll get a PR up that implements the hierarchical wild-card logic.
As noted in apisprout#1, this sample file fails to parse because the discriminator is an object instead of a string. It looks like the spec says it should be an object like in the linked example file.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.