Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oneOf matches more than one #ref or Property #369

Open
ramswish opened this issue Jun 11, 2021 · 6 comments
Open

oneOf matches more than one #ref or Property #369

ramswish opened this issue Jun 11, 2021 · 6 comments
Labels

Comments

@ramswish
Copy link

ramswish commented Jun 11, 2021

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
Copy link
Author

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
Copy link
Author

@fenollp pls check this and comment.

@fenollp fenollp added the bug label Jun 11, 2021
@fenollp
Copy link
Collaborator

fenollp commented Jun 11, 2021

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 #318 but we'll probably use https://github.com/qri-io/jsonschema/

@ramswish
Copy link
Author

ramswish commented Aug 2, 2022

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
Copy link
Author

ramswish commented Aug 3, 2022

@fenollp ?

@fenollp
Copy link
Collaborator

fenollp commented Dec 19, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants