GithubHelp home page GithubHelp logo

getkin / kin-openapi Goto Github PK

View Code? Open in Web Editor NEW
2.4K 23.0 412.0 1.56 MB

OpenAPI 3.0 (and Swagger v2) implementation for Go (parsing, converting, validation, and more)

License: MIT License

Go 99.06% Shell 0.94%
openapi openapi3 swagger api documentation golang hacktoberfest openapi2

kin-openapi's People

Contributors

alexandear avatar danicc097 avatar danielgtaylor avatar derekstrickland avatar disposedtrolley avatar fenollp avatar hottestseason avatar jban332 avatar k2tzumi avatar kandaaaaa avatar kconwayatlassian avatar micronull avatar mromaszewicz avatar nikolaas avatar orensolo avatar ori-shalom avatar orshlom avatar pruser avatar radwaretaltr avatar rikkkky avatar ronniedada avatar shouheinishi avatar slessard avatar stakme avatar tristanspeakeasy avatar tschaub avatar vasayxtx avatar wtertius avatar yarn-e avatar zekth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kin-openapi's Issues

Error when installing

$ 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)```

Deviation from official Open API 3.0 Documentation

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

query param with anyOf failed to parse

Openapi yaml with:

paths:
/resource-store:
get:
operationId: SearchResources
tags:

  • Resource Store)
    parameters:
  • name: resource-type
    in: query
    description: Type of the resource to get
    required: true
    schema:
    $ref: '#/components/schemas/RESOURCEType'
    responses:
    xxxx

components:
schemas:
RESOURCEType:
anyOf:

  • type: string
    enum:
  • MEM
  • CPU
  • DISK
  • type: string

====
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

Response Validation Does Not Validate Response Property types

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

Decode ExtensionProps (OAP 3)

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 !

bearerFormat in securitySchemes isn't validated according to spec

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:

switch ss.BearerFormat {

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.

Add DefineNumberFormat function

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.

Link type has no OperationRef field

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.

Request Validator Checks `readOnly` Properties

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.

Request validation does not work correctly with "additionalProperties: false"

Background

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.

Problem

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

Steps to reproduce

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)
	}
}

Result

  • first test will fail with "Property 'prop3' is unsupported" (correct)
  • second test will pass (incorrect)

openapi3: TestLoadFromRemoteURL panics when TCP port 3000 is in use

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.

Paths ending with an extension aren't matched

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:
      # ...

Request validation does not work correctly with anyOf

Problem

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

Swagger v2 to v3 conversion

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 bypass route validation and do schema only?

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.

Read schema with refs

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

versus swaggo and swagger?

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.

Support for full validation of operation's parameters

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.

Empty scopes is invalid for OpenAPI 3

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.

Unsupported 'format' value

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)

securitySchema.flow is correctly flows

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?

Let's remove package 'jsoninfo'

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.

Leading slash in path is not mandatory

By OpenAPI 3.0.0 specification Paths Object path have description - "The field name MUST begin with a slash".

But kin-openapi/openapi3 can handle such docs:

        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

Header type should have the same fields as Parameter

Hi,

I'm dinning in OpenAPIv3 spec and just figured out that Header object fields should be the same as in Parameter.

Header Object :

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).

discriminator mapping should contain strings, not schema ref objects

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")
	}
}

Invalid validation of allOf combined with additionalProperties: false

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.

Expand a spec

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.

Any plans on supporting YAML?

BTW the readme says

openapi3.NewSwaggerLoader().LoadFromFile

while it should read

openapi3.NewSwaggerLoader().LoadSwaggerFromFile

Tight loop due to circular reference between two yaml files

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?

Request validation does not work correctly with discriminator

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")
	}
}

"Required" validation does not work correctly with a request's body

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.

Steps to Reproduce the Problem (including complete and simple design if relevant)

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")
}

Actual Behavior

Function openapi3filter.ValidateRequest returns nil.

Expected Behavior

Function openapi3filter.ValidateRequest returns *openapi3filter.RequestError.

Specifications

kin-openapi version: commit 9acc5e9.

Preserving order of parsed OpenAPI?

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 {
}

Request validation fails on localhost

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.

References outside #/components/... fail to parse

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.

Schema validation messages

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'.

Not correctly decoding map with nested array of object

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?

A complex parameter using content in paths validator will failed

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 !

Benthos

Are you using Benthos with this ?

Request validation doesn't support content-type wildcards

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.