When discriminator validation fails the subreport is not propagated up to the ValidationReport returned by the OpenApiInteractionValidator

Issue #316 resolved
Simon Brown created an issue

Hi

We are using your project to validate message content passed on our network, there are a number of message types which share many common properties, but differ in various ways.

I have found that if I define my Message object as follows (sanitized slightly), then as long as the discriminator is provided correctly the message will be validated against the correct object.

I originally tried to use oneOf combined with the discriminator, but that didn't have the desired result, it would just say it failed to validate against 0 of 3 and would list the reasons for failure against each of the possible subtypes. This seemed strange to me since the discriminator was supplied and should have been used to validate against a single sub-type only.

The below works for me, but for one issue:

components:
  schemas:
    Message:
      type: object
      required:
        - message_type
      properties:
        message_type:
          type: string
      discriminator:
        propertyName: message_type
        mapping:
          MessageType1: '#/components/schemas/MessageType1'
          MessageType2: '#/components/schemas/MessageType2'
          MessageType3: '#/components/schemas/MessageType3'


    Payload:
      type: object
      properties:
        messages:
          type: array
          items:
            $ref: '#/components/schemas/Message'



  /messages/consume:
    post:
      operationId: msgConsumeV1
      summary: Consumes messages
      security:
        - jwt: []
    responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payload'

The issue I am having is if the validation fails in the validator\schema\keyword\DiscriminatorKeywordValidator.java because the message doesn’t conform to the definition that the discriminator specifies, then it will generate a subReport invalidateAllOfComposition however that subReport is then not processed when the main ValidationReport is created. As you can see in the debugger, the subReport has the correct reason for the failure to validate:

But the useful content of that sub-report is then omitted from the validation report that the OpenApiInteractionValidator returns, which unfortunately means end user has no idea what it was about their message that was wrong:

{
  "messages" : [ {
    "key" : "validation.request.body.schema.discriminator",
    "level" : "ERROR",
    "message" : "[Path '/messages/0'] Failed validation of discriminator schema '/components/schemas/MessageType1'",
    "context" : {
      "requestPath" : "/trade/messages/publish",
      "apiRequestContentType" : "application/json",
      "location" : "REQUEST",
      "requestMethod" : "POST"
    }
  } ]
}

I think it is possibly because in validateAllOfComposition the following code is executed:

        if (!subReport.isSuccess()) {
            report.error(msg(data, bundle, "err.swaggerv2.discriminator.fail")
                    .putArgument("schema", ptrToChildSchema.toString())
                    .put("report", subReport.asJson()));
        }

Note that it puts the sub-report as json into the report with the key name of “report”.

However when the report is processed and turned into the main validation report, the following code is run in validator/schema/SchemaValidator.java (in the method toValidationReportMessage) and as you can see if it looking for the key name of “reports”, which means the json sub-report is never put into the main report (since its key name is “report”), which means valuable validation failure information is lost:

        final List<String> subReports = new ArrayList<>();
        if (processingMessage.has("reports")) {
            final JsonNode reports = processingMessage.get("reports");
            reports.fields().forEachRemaining(field -> {
                field.getValue().elements().forEachRemaining(report -> {
                    subReports.add(field.getKey() + ": " + capitalize(report.get("message").textValue()));
                });
            });
        }

Would the solution to this problem simply be a case of ensuring that in validator\schema\keyword\DiscriminatorKeywordValidator.java in the method toValidationReportMessage, the sub-report is added to the main report using the key name of “reports”?

        if (!subReport.isSuccess()) {
            report.error(msg(data, bundle, "err.swaggerv2.discriminator.fail")
                    .putArgument("schema", ptrToChildSchema.toString())
                    .put("reports", subReport.asJson()));
        }

that way, as far as I am able to tell, the sub-report should then feature in the main report.

Keen to hear your thoughts on the above, and am happy to provide more detail as necessary.

Comments (4)

  1. Log in to comment