Validation of response fails if there are writeOnly fields that are marked as required

Issue #268 resolved
Arho Huttunen created an issue

Tried searching for similar issues, but didn’t find this exact case. There seem to have been other slightly similar issues though.

Using the mockmvc validator, with the following schema:

type: object
required:
  - someField
properties:
  someField:
    type: string
    writeOnly: true

The response validation fails with:

{
  "messages" : [ {
    "key" : "validation.response.body.schema.required",
    "level" : "ERROR",
    "message" : "Object has missing required properties ([\"someField\"])",
    "context" : {
      "requestPath" : "/some-endpoint",
      "responseStatus" : 200,
      "location" : "RESPONSE",
      "requestMethod" : "POST"
    }
  } ]
}

So the validation is not respecting the fact that the field is a request-only field.

From OpenAPI documentation:

If a readOnly or writeOnly property is included in the required list, required affects just the relevant scope – responses only or requests only. That is, read-only required properties apply to responses only, and write-only required properties – to requests only.

Comments (13)

  1. James Navin

    Can you please let me know what version you are using. There were some recent improvements to the behavior of readOnly/ writeOnly with required released in v2.9.1.

  2. Arho Huttunen reporter

    Unfortunately this still happens with 2.9.1. Do you have enough information here, or do you need more?

  3. James Navin

    Hmm. Odd. There are test cases that cover almost exactly this. I will have to dig a bit deeper.

    A full API spec + request example might be useful.

  4. James Navin

    Hi Arho,

    The way those tests work is a perhaps a little misleading. They load the OpenAPI spec, then invoke the schema validator with the specific schema fetched from the #/components/schemas block. You can see in e.g. https://bitbucket.org/atlassian/swagger-request-validator/src/78393640b5492604ded5c7f31b4fdaca6b355635/swagger-request-validator-core/src/test/java/com/atlassian/oai/validator/schema/SchemaValidatorTest.java#lines-662 that the ReadOnlyAllOf schema is being used to validate the provided input object.

    Could you supply an example schema + request + error that reproduces the problem?

    Cheers,

    James

  5. Arho Huttunen reporter

    This is actually a little different issue from what has been described here, but here’s how to reproduce. Still related to allOf, readOnly, writeOnly, complains about additional properties in the response.

    Schema:

    openapi: 3.0.1
    info:
      title: Some API
      version: 1.0.0
    paths:
      /resource:
        get:
          parameters:
            - $ref: '#/components/parameters/collectionPage'
            - $ref: '#/components/parameters/collectionSize'
          responses:
            '200':
              description: OK
              content:
                application/vnd.company-1.0+json:
                  schema:
                    $ref: '#/components/schemas/ResourceCollection'
    components:
      schemas:
        ResourceId:
          type: string
        Resource:
          type: object
          required:
            - name
          properties:
            id:
              allOf:
                - $ref: '#/components/schemas/ResourceId'
              readOnly: true
            name:
              minLength: 1
              type: string
        Page:
          type: object
          properties:
            size:
              type: integer
              format: int32
            totalElements:
              type: integer
              format: int32
            totalPages:
              type: integer
              format: int32
            number:
              type: integer
              format: int32
        ResourceCollection:
          type: object
          properties:
            content:
              type: array
              items:
                $ref: '#/components/schemas/Resource'
            page:
              type: object
              allOf:
                - $ref: '#/components/schemas/Page'
      parameters:
        collectionPage:
          name: page
          in: query
          schema:
            type: integer
            format: int32
        collectionSize:
          name: size
          in: query
          schema:
            type: integer
            format: int32
    

    Request GET /resource?page=1&size=10 with Accept header application/vnd.company-1.0+json.

    Response with application/vnd.company-1.0+json content type:

    {
      "links": [
        {
          "rel": "first",
          "href": "http://localhost/resource?page=0&size=10"
        },
        {
          "rel": "prev",
          "href": "http://localhost/resource?page=0&size=10"
        },
        {
          "rel": "self",
          "href": "http://localhost/resource?page=1&size=10"
        },
        {
          "rel": "next",
          "href": "http://localhost/resource?page=2&size=10"
        },
        {
          "rel": "last",
          "href": "http://localhost/resource?page=2&size=10"
        }
      ],
      "content": [
        {
          "id": "ae903586-6bb6-48a3-801b-2b5d29417c76",
          "name": "Resource name",
          "links": [
            {
              "rel": "self",
              "href": "http://localhost/resource/ae903586-6bb6-48a3-801b-2b5d29417c76"
            }
          ]
        }
      ],
      "page": {
        "size": 10,
        "totalElements": 21,
        "totalPages": 3,
        "number": 1
      }
    }
    

    Error:

    {
        "key" : "validation.response.body.schema.additionalProperties",
        "level" : "ERROR",
        "message" : "[Path '/page'] Object instance has properties which are not allowed by the schema: [\"number\",\"size\",\"totalElements\",\"totalPages\"]",
        "context" : {
          "requestPath" : "/resource",
          "responseStatus" : 200,
          "location" : "RESPONSE",
          "requestMethod" : "GET"
        }
      }
    

    There’s also a whitelisting rule to ignore the links in there:

                .withRule(
                    "Ignore additional properties that are HATEOAS links",
                    allOf(
                        messageHasKey("validation.response.body.schema.additionalProperties"),
                        messageContains("\\[\\\"links\\\"\\]") // This is regex based, not string match!
                    )
                )
    

  6. James Navin

    Ah I see. I think you are now falling victim to a known problem with allOf and additionalProperties validation. Please take a look at the FAQ https://bitbucket.org/atlassian/swagger-request-validator/src/master/docs/FAQ.md which has details.

    I should have called this out in the release notes actually - v2.9.1 fixed a bug where the additionalProperties validation was not being propagated properly to nested schemas etc. It looks like your schema is now falling victim to that.

    Please try out the suggestion in the FAQ - if that doesn’t work please raise a new issue and we can look at alternative ways to deal with it.

    Cheer,

    James

  7. Arho Huttunen reporter

    Yes, that seems to “work”. Unfortunately we have used composition quite a bit in the schemas, and this now exposes all those problems. Ignoring the additional properties seem to defy the purpose of validation in our case.

    Anyway, the original issue described here seems to be fixed in 2.9.1 so I’ll create a new issue.

  8. Log in to comment