Fix validate pacts with openAPI 3.0.3 spec with oneOf list
Issue #94
invalid
Is not posible to validate a pact against an openAPI spec 3.0.3 with the use of oneOf in the response. Only validates if the list of “oneOf” has one element.
schema:
type: "object"
oneOf:
- $ref: "#/components/schemas/read"
- $ref: "#/components/schemas/readDetail"
Simple example:
The openAPI
openapi: 3.0.3
info:
title: example-api
description: |
Example Public API.
version: 0.3.0-SNAPSHOT
license:
name: mylicense
url: https://mydomain.com/license
servers:
- url: https://mydomain.com/service
paths:
/read/1:
get:
summary: "Read one item"
operationId: "read"
responses:
"200":
description: OK
content:
application/json:
schema:
type: "object"
oneOf:
- $ref: "#/components/schemas/read"
- $ref: "#/components/schemas/readDetail"
components:
schemas:
read:
properties:
number:
type: integer
format: int32
example: 12
readDetail:
properties:
number:
type: integer
format: int32
example: 12
remarks:
type: string
example: "A description"
The pact:
{
"consumer": {
"name": "consumer-sync"
},
"interactions": [
{
"description": "Read item",
"request": {
"matchingRules": {
"path": {
"combine": "AND",
"matchers": [
{
"match": "regex",
"regex": "/read/1"
}
]
}
},
"method": "GET",
"path": "/read/1"
},
"response": {
"body": {
"number": 100
},
"generators": {
"body": {
"$.number": {
"max": 2147483647,
"min": 0,
"type": "RandomInt"
}
}
},
"headers": {
"Content-Type": "application/json"
},
"matchingRules": {
"body": {
"$.number": {
"combine": "AND",
"matchers": [
{
"match": "number"
}
]
}
}
},
"status": 200
}
}
],
"metadata": {
"pact-jvm": {
"version": "4.3.9"
},
"pactSpecification": {
"version": "3.0.0"
}
},
"provider": {
"name": "provider-sync"
}
}
The error:
1 error(s)
response.body.incompatible: 1
0 warning(s)
{
warnings: [],
errors: [
{
code: 'response.body.incompatible',
message: 'Response body is incompatible with the response body schema in the spec file: should match exactly one schema in oneOf',
mockDetails: {
interactionDescription: 'Read item',
interactionState: '[none]',
location: '[root].interactions[0].response.body',
mockFile: 'pacts/consumer-sync-provider-sync.json',
value: { number: 100 }
},
source: 'spec-mock-validation',
specDetails: {
location: '[root].paths./read/1.get.responses.200.content.application/json.schema.oneOf',
pathMethod: 'get',
pathName: '/read/1',
specFile: 'openapitest.yml',
value: [
{
properties: {
number: { type: 'integer', format: 'int32', example: 12 }
}
},
{
properties: {
number: { type: 'integer', format: 'int32', example: 12 },
remarks: { type: 'string', example: 'A description' }
}
}
]
},
type: 'error'
}
]
}
Comments (3)
-
Account Deactivated -
Account Deactivated - changed status to invalid
working as expected
-
Account Deactivated reporter That’s interesting, It would be great to clarify this en the documentation, because generates confusion. I would use anyOf. Thanks!
- Log in to comment
@{557058:5c25f91c-c8f3-4a13-9254-7dfe9e35b82b} , the library seems to be doing the right thing.. oneOf is a XOR.. any values must much one and only one of the schemas in the list. the example in the pact file
{number: 100}
matches both of the schemas in the oneOf. (in the second schemaremarks
is not required, sot it can be missing)Even if you had
{number: 100, remarks: "foo"}
that would match both schemas, since the first schema accepts any additional properties.most values will never match your oneOf since they are not mutually exclusive. (Actually the following will match
{number: 100: remarks: ["not", "a", "string"]}
but I guess that wasn’t your intention)You can either fix the schemas in the list, or maybe what you are really after is an
anyOf
.. which to be honest you don’t even need, having the second schema is enough.Check the json schema specification for details