Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Does Not Support Binary Response Types #854

Open
its-hammer-time opened this issue Jun 13, 2024 · 3 comments
Open

[Bug]: Does Not Support Binary Response Types #854

its-hammer-time opened this issue Jun 13, 2024 · 3 comments
Labels
kind/bug Indicates an issue

Comments

@its-hammer-time
Copy link

its-hammer-time commented Jun 13, 2024

Actual Behavior

I hacked together the code below so that I could test this library in isolation, but for context we are using it inside of a Pyramid app. When I run the case below, I get the following exception:

openapi_core.validation.response.exceptions.InvalidData: InvalidData: Value b'<pdf_content>' not valid for schema of type string: (<ValidationError: "b'<pdf_content>' is not of type 'string'">,)

If I then try to wrap it inside of a str(), I get is not of type 'binary' so I believe there is an issue with the formatter understanding the bytes as a string.

Expected Behavior

If I return a binary object (pdf file) it should pass validation.

Steps to Reproduce

import typing as t

from openapi_core import OpenAPI
from openapi_core.validation.request.datatypes import RequestParameters


class OpenAPIRequest:
    def __init__(self) -> None:
        self.parameters = RequestParameters(
            path={},
            query={},
            header={},
            cookie={},
        )

    @property
    def host_url(self) -> str:
        return "https://example.com"

    @property
    def path(self) -> str:
        return "/test"

    @property
    def path_pattern(self) -> str:
        return "/test"

    @property
    def method(self) -> str:
        return "get"

    @property
    def body(self) -> t.Optional[t.Union[bytes, str, t.Dict]]:
        return None

    @property
    def content_type(self) -> str:
        return ""

    @property
    def mimetype(self) -> str:
        return ""


class OpenAPIResponse:
    def __init__(self, data: any) -> None:
        self._data = data

    @property
    def data(self) -> t.Optional[bytes]:
        return self._data

    @property
    def status_code(self) -> int:
        return 200

    @property
    def content_type(self) -> str:
        return "application/pdf"

    @property
    def mimetype(self) -> str:
        return "application/pdf"

    @property
    def headers(self) -> t.Mapping[str, t.Any]:
        return {
            "Content-Type": "application/pdf",
            "Content-Disposition": "attachment; filename=invoice.pdf",
        }


if __name__ == "__main__":
    with open('example-pdf.pdf', 'rb') as f:
        pdf_content = f.read()

    open_api_spec = OpenAPI.from_dict({
        "openapi": "3.1.0",
        "info": {
            "title": "Test spec",
            "version": "1.0.0",
            "description": "Test spec",
        },
        "servers": [
            {"url": "https://example.com"},
        ],
        "paths": {
            "/test": {
                "get": {
                    "responses": {
                        "200": {
                            "description": "OK",
                            "content": {
                                "application/pdf": {
                                    "schema": {
                                        "type": "string",
                                        "format": "binary",
                                    },
                                },
                            },
                        },
                    },
                },
            }
        }
    })

    request = OpenAPIRequest()
    response = OpenAPIResponse(data=pdf_content)
    open_api_spec.validate_response(request=request, response=response)

OpenAPI Core Version

0.19.1

OpenAPI Core Integration

Natively using openapi-core

Affected Area(s)

Validation

References

No response

Anything else we need to know?

No response

Would you like to implement a fix?

None

@its-hammer-time its-hammer-time added the kind/bug Indicates an issue label Jun 13, 2024
@its-hammer-time
Copy link
Author

I tried adding a deserializers for the mimetype, but it's complaining that it's no longer "binary".

    def deserialize_pdf(value: bytes) -> str:
        return value.decode("utf-8")


    open_api_config: Config = Config(
        extra_media_type_deserializers={
            "application/pdf": deserialize_pdf,
        }
    )

    open_api_spec = OpenAPI.from_dict({ ... }, config=open_api_config)

If it's binary the library complains that it's not a 'string' and if it's a string it complains that it's not 'binary'

@p1c2u
Copy link
Collaborator

p1c2u commented Jun 25, 2024

Hi @its-hammer-time

thanks for the report. it's a known issue that will requires breaking change #647

@p1c2u
Copy link
Collaborator

p1c2u commented Jul 2, 2024

After further investigation the problem exist with Openapi 3.1.

If you change to openapi 3.0.3 it works 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Indicates an issue
Projects
None yet
Development

No branches or pull requests

2 participants