How to create a swagger:response that produces a binary application/pdf file?

Viewed 9716

I'm failing in getting a file download working in swagger, connexion, openapi3. Within the openapi specification I've defined the following path:

/lab/samples/list/pdf:
get: 
  summary: download pdf file
  operationId: get_sample_pdf
  responses:
    "200":
        application/pdf:
          schema:
            type: string
            format: binary  
  security:
  - labuserAuth: []
  x-openapi-router-controller: swagger_server.controllers.lab_controller#

The call is forwarded to my lab_controler.py which simplay returns the binary pdf

def list_sample_pdf():
    f_pdf = "list_samples.pdf"
    with open(f_pdf, "rb") as f:
        return f.read()

When calling the endpoint I receive

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xdf in position 10: invalid continuation byte

As I was looking for answers I stumbled upon a bunch of different threads, but non of them could really give me a hint on what I'm doing wrong

What configurations are required on the openapi side? And what should my controller implementation be retourning, so that connexion is able to properly handle the pdf?

This is how I run the application

    app = connexion.App(__name__, specification_dir='./swagger/')
    app.json_encoder = encoder.JSONEncoder
    app.add_api('swagger.yaml', arguments={'title': 'sample-submission and notification service'}, pythonic_params=True)

    #add CORS support to send Access-Control-Allow-Origin header
    CORS(app.app,expose_headers=["Content-Disposition: "])
    app.run(host="127.0.0.1", port=8083)

I also tried adding an application/octet-stream response

application/octet-stream:
                  encoding:
                    file:
                      headers:
                        Content-Disposition:
                          schema:
                            type: string
                            format: binary
                            example: attachment; filename="name.pdf"

When instead of returning a pdf file, with open(f_csv, "rb") as f: return f.read() a UTF-8 readable file as this simple csv file, te the content of the non binary file is returned by connexion as application/json response

2 Answers

Have you tried adding a header definition?

paths:          
  /examples:
    get:
      responses:
        '200':
          description: ok
          content:
            application/pdf:
              schema:
                type: string
                format: binary
          headers:
            Content-Disposition:
              schema:
                type: string
                description: Used only with `application/pdf` responses
                example: attachment; filename="name.pdf"

as a non very elegant workaround you can do the following to return :

 import flask, os
    
    resp = flask.send_from_directory(os.path.abspath(os.getcwd()), 'file_to_send.pdf',
            as_attachment=True, 
            mimetype='application/pdf',
            attachment_filename='your_pdf_name.pdf'
        )

    return flask.Response(
            response = resp.response,
            status=200,
            content_type='application/pdf',
            headers=resp.headers,
            mimetype=resp.mimetype
        )
Related