kin-openapi icon indicating copy to clipboard operation
kin-openapi copied to clipboard

oneOf matches more than one #ref or Property

Open ramswish opened this issue 4 years ago • 6 comments

when i try to test oneOf under reference object, it matches single individual input data with all the schemas under oneOf and giving error as below.

request body has an error: doesn't match the schema: input matches more than one oneOf schemas

verrsion i have used

github.com/getkin/kin-openapi v0.63.0

yaml i have used attached


openapi: 3.0.0 info: title: test 123 description: description contact: email: [email protected] license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html version: 1.0.1 tags:

  • name: testOneof description: Everything paths: /testOneof: patch: tags: - testOneof summary: modify subscriber in network elements description: | This API is used to create operationId: testOneof requestBody: content: application/json: schema: $ref: '#/components/schemas/ModifyData' responses: "202": description: Request for .

components: schemas: ModifyData: required: - '@type'
- neModifyData type: object properties: '@type': maxLength: 64 minLength: 2 type: string example: neModifyData default: neModifyData neModifyData: $ref: '#/components/schemas/neModifyData' neModifyData: type: object oneOf: - properties: accountStatus: type: string description: Account status of this subscriber example: active default: active enum: - active - suspended - properties: subscriberType: type: string enum: - PRE - POST - POST - HYBRID - properties: oneData : $ref: '#/components/schemas/oneData'
- properties: twoData: $ref: '#/components/schemas/twoData' - properties: threeData: $ref: '#/components/schemas/threeData'

oneData:
  type: object
  properties:
    oneDataService: 
      type: string
      minLength: 1
      maxLength: 20
twoData:
  type: object
  properties:
    twoDataService: 
      type: string
      minLength: 1
      maxLength: 20
threeData:
  type: object
  properties:
    twoDataService: 
      type: string
      minLength: 1
      maxLength: 20

securitySchemes: basicAuth: type: http scheme: basic

sample inputs used for testing below. for any oneof data it is giving error.

{ "@type": "neModifyData", "neModifyData": { "accountStatus": "active" } }

{ "@type": "neModifyData", "neModifyData": { "subscriberType": "POST" } }

Golang server code used

`package main

import ( "context" "fmt"

"net/http"

"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"

)

func requestHandler(response http.ResponseWriter, request *http.Request) { fmt.Println("received request") ctx := context.Background() loader := &openapi3.Loader{Context: ctx} doc, _ := loader.LoadFromFile("openapi_modify.yaml") err := doc.Validate(ctx) if err != nil { fmt.Println("doc.Validate Error:", err) return }

router, _ := legacyrouter.NewRouter(doc)

// Find route
route, pathParams, _ := router.FindRoute(request)

// Validate request
requestValidationInput := &openapi3filter.RequestValidationInput{
	Request:    request,
	PathParams: pathParams,
	Route:      route,
}

if err := openapi3filter.ValidateRequest(ctx, requestValidationInput); err != nil {
	fmt.Println("Request Validation Failed!!!", err)
} else {
	fmt.Println("Request Validation Success!!!")
}

}

func main() {

http.HandleFunc("/", requestHandler)

http.ListenAndServe(":8090", nil)

} `

ramswish avatar Jun 11 '21 03:06 ramswish

Analyzed code with some prints and found issue in visitJSONObject() function in schema.go file

in visitJSONObject function, if it gets the propertyRef it is validating, if the propertyRef is not found then it function would return success all the time.

this function will be called from visitSetOperations for all the oneof schemas, in which for all the schemas it returns success and fianlly visitSerOperations fuction has logic to fail if it is success for all the schema to fail.

visitSetOperations

for k, v := range value { if properties != nil { propertyRef := properties[k] fmt.Printf("visitJSONObject: properties[k] : %v --> %v\n", k, *propertyRef) fmt.Printf("visitJSONObject: v : %v\n", v) if propertyRef != nil { p := propertyRef.Value if p == nil { return foundUnresolvedRef(propertyRef.Ref) } if err := p.visitJSON(settings, v); err != nil { if settings.failfast { return errSchema } err = markSchemaErrorKey(err, k) if !settings.multiError { return err } if v, ok := err.(MultiError); ok { me = append(me, v...) continue } me = append(me, err) } continue } }

visitSetOperations

if v := schema.OneOf; len(v) > 0 { fmt.Println("visitSetOperations schema.OneOf len(v)", len(v)) ok := 0 for _, item := range v { v := item.Value fmt.Println("visitSetOperations value : ", v) if v == nil { return foundUnresolvedRef(item.Ref) } var oldfailfast bool oldfailfast, settings.failfast = settings.failfast, true err := v.visitJSON(settings, value) settings.failfast = oldfailfast if err == nil { fmt.Println("$$$$$$$$$$$ Got Success") if schema.Discriminator != nil { pn := schema.Discriminator.PropertyName if valuemap, okcheck := value.(map[string]interface{}); okcheck { if discriminatorVal, okcheck := valuemap[pn]; okcheck == true { mapref, okcheck := schema.Discriminator.Mapping[discriminatorVal.(string)] if okcheck && mapref == item.Ref { ok++ } } } } else { ok++ } } } fmt.Println("visitSetOperations Ok : ", ok) if ok != 1 { if settings.failfast { return errSchema } e := &SchemaError{ Value: value, Schema: schema, SchemaField: "oneOf", } if ok > 1 { e.Origin = ErrOneOfConflict } return e } }

Questions i have here is

  1. why visitJSONObject ignoring the fields which are not part of schema. this leads to schema validation success for the input data consist of elements which are not present in schema.
  2. i have checked commit log, this code is present from beginnig , is it done internsionally?

Solution i could think of

visitJSONObject should fail if propertyRef is not present for the incoming data. if solution looks fine i can push the change if you wish to.

ramswish avatar Jun 11 '21 03:06 ramswish

@fenollp pls check this and comment.

ramswish avatar Jun 11 '21 04:06 ramswish

At this point there are many issues with this project's own schema validation code. We're looking to replace this code with a third party's lib. Maybe take a look at https://github.com/getkin/kin-openapi/pull/318 but we'll probably use https://github.com/qri-io/jsonschema/

fenollp avatar Jun 11 '21 13:06 fenollp

Hi @fenollp , any workaround we have for this issue? if you can estimate how much effort we need on supporting jsonschema may be i can try to contribute.

ramswish avatar Aug 02 '22 05:08 ramswish

@fenollp ?

ramswish avatar Aug 03 '22 05:08 ramswish

Hi there! Could you send a PR with your changes and a regression test?

fenollp avatar Dec 19 '22 16:12 fenollp