3

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

user5198729
  • 19
  • 1
  • 1
  • 3
  • Add the `content:` node between `"200":` and `application/pdf:` in the response definition. Does this help? – Helen Sep 22 '20 at 20:32

3 Answers3

0

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"
Ichwardort
  • 121
  • 1
  • 7
0

From https://swagger.io/docs/specification/describing-responses/

paths:
 get:
  summary: Returns the report in the PDF format
  responses:
    '200':
      description: A PDF file
      content:
        application/pdf:
          schema:
            type: string
            format: binary
-1

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
        )
Ichwardort
  • 121
  • 1
  • 7