maximdanilchenko / aiohttp-apispec

Build and document REST APIs with aiohttp and apispec
https://aiohttp-apispec.rtfd.io
MIT License
220 stars 57 forks source link

Is it possible to specify a binary file response? #91

Open sklump opened 4 years ago

sklump commented 4 years ago

We have an admin API with a function to download a (binary) file.

This specification

@docs(
    tags=["revocation"],
    summary="Download the tails file of revocation registry",
    produces="application/octet-stream",
    responses={200: {"description": "tails file", "schema": {"type": "string", "format": "binary"}}},
)
async def get_tails_file(reqeuest: web.BaseResquest):
    """..."""

fails on startup because the "schema" is not a Marshmallow schema:

    ...
    await runner.setup()
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp/web_runner.py", line 232, in setup
    self._server = await self._make_server()
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp/web_runner.py", line 331, in _make_server
    await self._app.startup()
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp/web_app.py", line 389, in startup
    await self.on_startup.send(self)
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp/signals.py", line 34, in send
    await receiver(*args, **kwargs)  # type: ignore
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp_apispec/aiohttp_apispec.py", line 77, in doc_routes
    self._register(app_)
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp_apispec/aiohttp_apispec.py", line 117, in _register
    self._register_route(route, method, view)
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp_apispec/aiohttp_apispec.py", line 131, in _register_route
    self._update_paths(view.__apispec__, method, self.prefix + url_path)
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/aiohttp_apispec/aiohttp_apispec.py", line 155, in _update_paths
    required=actual_params.get("required", False),
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/apispec/ext/marshmallow/openapi.py", line 130, in schema2parameters
    prop = self.resolve_nested_schema(schema)
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/apispec/ext/marshmallow/openapi.py", line 90, in resolve_nested_schema
    schema_instance = resolve_schema_instance(schema)
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/apispec/ext/marshmallow/common.py", line 24, in resolve_schema_instance
    return marshmallow.class_registry.get_class(schema)()
  File "/home/indy/.pyenv/versions/3.6.9/lib/python3.6/site-packages/marshmallow/class_registry.py", line 74, in get_class
    classes = _registry[classname]

Is there any way to mark a registered method to output OpenAPI docs specifying that its output is a binary file?

I've tried specifying an empty marshmallow schema like this

class TailsFileResponseSchema(Schema):
    """..."""

# ...

@docs(
    tags=["revocation"],
    summary="Download the tails file of revocation registry",
    produces="application/octet-stream",
    responses={200: {"description": "tails file", "schema": TailsFileResponseSchema()}},
)
async def get_tails_file(reqeuest: web.BaseResquest):
    """..."""

and then using the @pre_load/@post_load/@pre_dump/@post_dump/@validates_schema/@validate decorators to populate the response schema with {"type": "string, "format": "binary"}, but I can't get the server startup process to call them.

I've tried specifying the type and format as fields.Constant in the response schema, but that is not correct either of course, as it specifies a JSON object with type and format attributes, not a binary file.

Has anyone ever done this kind of thing? I would be very grateful for any advice.

mickours commented 3 years ago

I'm looking for the exact same thing and I can't find a way to simply give the "type: file" value.

I'd like to produce this specification documented in the Swagger V2 documentation:

    paths:
      /logo:
        get:
          summary: Returns the logo image
          produces:
            - image/png
            - image/gif
            - image/jpeg
          responses:
            200:
              description: OK
              schema:
                type: file

@sklump Did find an answer to this issue?