noirbizarre / flask-restplus

Fully featured framework for fast, easy and documented API development with Flask
http://flask-restplus.readthedocs.org
Other
2.73k stars 506 forks source link

Return PNG image from GET route #392

Open donfmorrison opened 6 years ago

donfmorrison commented 6 years ago

flask-restplus==0.10.1

Route always returns Content-Type: 'application/json' but need it to return 'image/png'

I realize for this example I could just have the client call the static image somefile.jpg to be served, but I'll use something like io.BytesIO(enc_im_bytes) for the *fp in real life and I don't expect the image itself to be stored on disk. Just using an image file in this example to simplify!

The following route always throws exception of TypeError: Object of type 'Response' is not JSON serializable

from flask import send_file
from flask_restplus import Resource
# ...
ns = api.namespace('Media', description='Operations related to media processing')
# ...
@ns.route('/Snapshot')
class MediaSnapshotImage(Resource):
    @api.response(200, 'Image returned.')
    def get(self):
        return send_file(
            'somefile.jpg',
            mimetype='image/png',
            attachment_filename='snapshot.png',
            cache_timeout=0
        ), 200

If I just use a regular flask route on the app, it works fine and returns the image; but this of course does not get documented by Swagger!

@app.route('/Media/Snapshot')
def get_image():
    return send_file(
        'somefile.jpg',
        mimetype='image/png',
        attachment_filename='snapshot.png',
        cache_timeout=0
    )

Maybe I am using flask-restplus wrong in this case?!

Any suggestions?

aparamon commented 6 years ago

As per https://github.com/noirbizarre/flask-restplus/issues/43 , @api.doc(model=[str]) should be specified to make Swagger-UI provide "Response Content Type" list-box for plain-text representations. It is not obvious what model should be specified for binary files though.

aparamon commented 6 years ago

For me, send_file(open(filename, 'rb')) does work in flask-restplus 1.10.

But indeed, Swagger docs mistakenly suggest that "application/json" is returned. I think what you are looking for is http://flask-restplus.readthedocs.io/en/stable/api.html#flask_restplus.Api.representation (implemented as no-op for this scenario); the limitation is that representations are not route-specific but rather global to app/namespace. I believe it would be sensible if available mediatypes could be customized on route level.

@noirbizarre What do you think?

robertofalk commented 6 years ago

Any updates on that?

bonashen commented 5 years ago

@aparamon For me, I use the code,can send png file.

    @ns.doc(description='generate qrcode image.')
    @ns.expect(request_parser)
    @ns.response(200, description='return qr-code PNG image file.')
    @ns.produces(['image/png'])
    def get(self):
        args = self.request_parser.copy().parse_args()
        return send_qrcode_file(**args)