OneOf doesn't seem to work as schema
In a post, this seems to fail:
post:
requestBody:
description: Object
required: true
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Obj1'
- $ref: '#/components/schemas/Obj2'
- $ref: '#/components/schemas/Obj3'
I checked the features list and oneOf seems to be supported but nothing but empty payloads seem to pass this swagger validation.
Comments (9)
-
-
reporter For sure, let me get that for you
-
reporter Here you go James:
openapi: "3.0.0" info: description: Auth Api Documentation version: "1.0.0" title: Api Documentation contact: {} servers: - url: https://example.com" description: prod - url: https://stage.example.com" description: Staging paths: /integrations: get: tags: - integration-controller operationId: IntegrationsController.index summary: Get Account Integrations description: > Returns the integrations configured for the account. parameters: - in: query name: accountId schema: type: string required: false responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/ArrayOfIntegrations' '401': description: Unauthorized '403': description: Forbidden post: operationId: create Integrations tags: - integration-controller summary: Create Account Integrations description: Create a new account integration parameters: - in: query name: accountId schema: type: integer required: false requestBody: description: Integration Object required: true content: application/json: schema: oneOf: - $ref: '#/components/schemas/AdobeSharedSecret' - $ref: '#/components/schemas/AdobeOAuthSupport' - $ref: '#/components/schemas/BitlyUrl' responses: '201': description: Creation Successful content: application/json: schema: $ref: '#/components/schemas/Integration' '401': description: UnAuthorized '403': description: Forbidden components: schemas: ArrayOfIntegrations: type: array items: $ref: '#/components/schemas/Integration' Integration: oneOf: - $ref: '#/components/schemas/AdobeSharedSecret' - $ref: '#/components/schemas/AdobeOAuthSupport' - $ref: '#/components/schemas/BitlyUrl' MetaDataDestination: type: object required: - type properties: name: type: string type: type: string URLShortener: type: object properties: name: type: string url: type: string AdobeSharedSecret: allOf: - $ref: '#/components/schemas/MetaDataDestination' - type: object required: - type properties: type: type: string enum: ["AdobeSharedSecret"] companyName: type: string reportSuites: $ref: '#/components/schemas/ArrayOfReportSuites' AdobeOAuthSupport: allOf: - $ref: '#/components/schemas/MetaDataDestination' - type: object properties: type: type: string enum: ["AdobeOAuthSupport"] companyName: type: string reportSuites: $ref: '#/components/schemas/ArrayOfReportSuites' BitlyUrl: allOf: - $ref: '#/components/schemas/URLShortener' - type: object properties: login: type: string apiKey: type: string companyName: type: string createdAt: type: string type: type: string enum: ["BitlyUrl"] ElementClassification: type: object properties: name: type: string ArrayOfReportSuites: type: array items: $ref: '#/components/schemas/ReportSuite' ReportSuite: type: object properties: rsid: type: string site_title: type: string element_classifications: $ref: '#/components/schemas/ElementClassification'
I believe this fails:
{ "name": "integration name", "type": "BitlyUrl", "provider": "bitly", "accountId": 1, "config": { } }
-
Which of the three top-level types are you expecting that one to match?
-
reporter Hey @James Navin ,
I decided to actually put together a good example instead of throwing something together last second. Here is the yaml file:
openapi: "3.0.0" info: description: Api Documentation version: "1.0.0" title: Api Documentation contact: {} servers: - url: https://example.com" description: Production - url: https://stage.example.com" description: Staging paths: /integrations: get: tags: - integration-controller operationId: IntegrationsController.index summary: Get Account Integrations description: > Returns the integrations configured for the account. For Admin, it returns the current account's settings For OP Admin, it can return any account's settings. For normal user, it returns 401. parameters: - in: query name: accountId schema: type: string required: false responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/ArrayOfIntegrations' '401': description: Unauthorized '403': description: Forbidden post: operationId: IntegrationsController.create tags: - integration-controller summary: Create Account Integrations description: > Create a new account integration parameters: - in: query name: accountId schema: type: integer required: false requestBody: description: Integration Object required: true content: application/json: schema: $ref: '#/components/schemas/Integration' responses: '201': description: Creation Successful content: application/json: schema: $ref: '#/components/schemas/IntegrationResponse' '401': description: UnAuthorized '403': description: Forbidden /integrations/{integrationId}: put: tags: - integration-controller operationId: Update Integration summary: Update Integration description: > Update an account integration parameters: - in: path name: integrationId schema: type: integer required: true - in: path name: accountId schema: type: integer required: true - in: query name: integration schema: $ref: '#/components/schemas/Integration' required: true requestBody: description: Integration Object required: true content: application/json: schema: oneOf: - $ref: '#/components/schemas/Integration' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Integration' '401': description: UnAuthorized '403': description: Forbidden delete: # operationId: Delete Integration tags: - integration-controller summary: Delete Integration description: > delete an account integration parameters: - in: path name: accountId schema: type: integer required: true - in: path name: integrationId schema: type: integer required: true responses: '200': description: Successful response content: application/json: schema: type: integer '401': description: UnAuthorized '403': description: Forbidden get: tags: - integration-controller summary: get Integration description: get a single account integration parameters: - in: path name: accountId schema: type: integer required: true - in: path name: integrationId schema: type: integer required: true responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Integration' '401': description: UnAuthorized '403': description: Forbidden /integration/{integrationId}/reconnect: post: tags: - integration-controller # operationId: reconnectIntegration summary: reconnectIntegation description: > reconnect an account integration and update status parameters: - in: path name: accountId schema: type: integer required: true - in: path name: integrationId schema: type: integer required: true responses: '200': description: Integration reconnected content: application/json: schema: type: string '401': description: UnAuthorized '403': description: Forbidden components: schemas: ArrayOfIntegrations: type: array items: $ref: '#/components/schemas/IntegrationResponse' IntegrationResponse: allOf: - $ref: '#/components/schemas/Integration' - type: object properties: lastUpdated: type: integer Integration: allOf: - type: object properties: name: type: string - type: object oneOf: - $ref: '#/components/schemas/UrlShortener' - $ref: '#/components/schemas/MetaDataDestination' MetaDataDestination: allOf: - type: object oneOf: - $ref: '#/components/schemas/AdobeOAuth' - $ref: '#/components/schemas/AdobeSharedSecret' - type: object properties: type: type: string enum: ["MetaDataDestination"] AdobeSharedSecret: type: object properties: provider: type: string enum: ["AdobeSharedSecret"] config: type: object properties: username: type: string secret: type: string AdobeOAuth: type: object properties: provider: type: string enum: ["AdobeOAuth"] BitlyUrl: allOf: - type: object properties: config: type: object properties: login: type: string apiKey: type: string companyName: type: string - type: object properties: provider: type: string enum: ["Bitly"] UrlShortener: allOf: - type: object properties: type: type: string enum: ["UrlShortener"] - $ref: '#/components/schemas/BitlyUrl' ElementClassification: type: object properties: name: type: string ArrayOfReportSuites: type: array items: $ref: '#/components/schemas/ReportSuite' ReportSuite: type: object properties: rsId: type: string rsLabel: type: string element_classifications: $ref: '#/components/schemas/ElementClassification'
Here is the payload:
{ "name": "integration name", "type": "MetaDataDestination", "provider": "AdobeOAuth" }
This should be valid and should match the Integration → MetaDataDestination → AdobeOAuth but the validator doesn’t work. This is the swagger validator response:
{ "messages" : [ { "key" : "validation.request.body.schema.additionalProperties", "level" : "ERROR", "message" : "Object instance has properties which are not allowed by the schema: [\"name\",\"provider\",\"type\"]", "context" : { "requestPath" : "/integrations", "apiRequestContentType" : "application/json", "location" : "REQUEST", "requestMethod" : "POST" } } ] }
[ERROR] [2020-01-14 17:42:42,380] [] OpenAPI location=REQUEST key=POST#/integrations levels=ERROR messages=Validation failed. [ERROR][REQUEST][POST /integrations @body] Object instance has properties which are not allowed by the schema: ["name","provider","type"]
-
Ah. You might be falling victim to a known problem with
additionalProperties
validation andallOf
,oneOf
etc.Please see the FAQ and let me know if that solves your problem - https://bitbucket.org/atlassian/swagger-request-validator/src/master/docs/FAQ.md.
-
Can I check whether the FAQ resolved your problem? If it does I’ll close out this ticket.
Cheers.
-
If anyone stumbles here, this workaround might work for you (in case you want exactly one of 3 types, without any extra properties):
SomeType: additionalProperties: true // to prevent using "false" during validation oneOf: - $ref: '#/components/schemas/Obj1' // these types can all define `additionalProperties: false` - $ref: '#/components/schemas/Obj2' - $ref: '#/components/schemas/Obj3'
-
- changed status to resolved
Closed due to inactivity. If this is still a problem please feel free to re-open.
- Log in to comment
Hi Jonathan,
Thanks for raising this. Could I please ask you to include a full spec (including the referenced schemas) and an example request you are using. This will help me to reproduce what you are seeing (there is reasonably good coverage of this feature in the test suite, but it is quite possible I’ve missed something).
Cheers,
James