eclipse-vertx/vertx-openapi

Not implemented media type "application/octet-stream" (OpenAPI 3.x)

Closed this issue · 12 comments

Version

io.vertx:vertx-openapi <= 4.5.9

Context

I encountered an exception which looks suspicious because the media type application/octet-stream is legit.
io.vertx.openapi.contract.OpenAPIContractException: The passed OpenAPI contract contains a feature that is not supported: Operation createBinary defines a request body with an unsupported media type. Supported: application/json, application/json; charset=utf-8, multipart/form-data, application/hal+json

Here is a migration guide on what has changed between OpenAPI 3.0 and 3.1:
https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0

Steps to reproduce

Have a openapi-contract.yml with the following snippet:

/api/v1/binary/{binaryId}:
  put:
    operationId: createBinary
    parameters:
      - name: binaryId
        in: path
        required: true
        schema:
          type: string
          pattern: '^[0-9a-f]{64}$'
    requestBody:
      required: true
      content:
        application/octet-stream: {}
    responses:
      '201':
        description: Resource created and stored on disk
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResourceRefBasedUponHash'
      '409':
        description: Resource already exists

Hi @sebveit, thanks for using Vert.x OpenAPI! Maybe the error message is a little bit misleading. It does not mean, that OpenAPI does not support this feature. It mean that Vert.x OpenAPI has not yet implemented support for this kind of content in the requestBody.

I've adapted the title of this issue to reflect that fact.

Is there a suggested way to work around this? e.g. a way to ignore unsupported content types?

My use case is adding an HTML representation to one of my endpoints (as the response).

Similar error:

io.vertx.openapi.contract.OpenAPIContractException: The passed OpenAPI contract contains a feature that is not supported: Operation getAll defines a response with an unsupported media type. Supported: application/json, application/json; charset=utf-8, multipart/form-data, application/hal+json
	at app//io.vertx.openapi.contract.OpenAPIContractException.createUnsupportedFeature(OpenAPIContractException.java:43)
	at app//io.vertx.openapi.contract.impl.ResponseImpl.<init>(ResponseImpl.java:77)

At the moment there is no work around, except disable validation. But we are working on a solution which allow you to do the follwoing:

3.1

requestBody:
  content:
    text/html: {}

3.0

requestBody:
  content:
    text/html:
      schema:
        type: string
        format: binary

@pk-work How do you disable validation?

@pk-work Thanks, but the OpenAPIContract.from part generates the error described in this issue, so I'm unable to reach the getRoute to disable validation

Mh, you are right. Okay, then you have to wait. I hope the fix will be ready in a few weeks.

@pk-work in this suggested change, would it then support all content types (text/csv, application/octet-stream, etc)?

It would be possible to support all content types, if someone is contributing the validation logic for all content types. But in case of application/octet-stream, no further validation / transformation is required. So in case the content type of interest is not yet supported, there is a way to "skip" the validation, by declaring it as application/octet-stream.

This is my current idea: For every supported content type we need an implementation of ContentAnalyser. In the Validator we will always check for syntactical correctness and then transform the body in case a validation is requested.

What about allowing the users to provide their own ContentAnalyser then? Similar to how the vertx-web-openapi allows additional BodyProcessorGenerator for unimplemented content types.

I think providing an own ContentAnalyser makes sense. But this would require that the information which content type is actually supported must retrieved dynamically and somehow passed to MediaType.isMediaTypeSupported(...). Because I still want to fail early if the contract defines things which are not yet supported by the library.