12

With python flask_restplus what is correct way to have a post and get methods to get and push a file e.g. xlsx to the server ?

Does the marshaling need to be used for this ?

reference: https://philsturgeon.uk/api/2016/01/04/http-rest-api-file-uploads/

This answer give general info but not in the python>flask>restplus context: REST API File Upload

Community
  • 1
  • 1
user3313834
  • 5,701
  • 4
  • 40
  • 76
  • 1
    My opinion can't succes with this module style if got multiple type/event on single post method. Send methods(file upload) is `post` but i never used this method because need check file content for writing somewhere ! is complex on big files, need synchronized source with target (not remove or move only making diff.). Some time need using additional revision on source code/html-output for dont losing any data or escape_multiple_io actions. Use Base64 encoded bz2 content if have small size files. Big files (which is big ?(on your server)) got a lot risks on create/modify proccess. – dsgdfg Nov 11 '16 at 12:28

1 Answers1

15

First you need to configure a parser

# parsers.py
import werkzeug
from flask_restplus import reqparse

file_upload = reqparse.RequestParser()
file_upload.add_argument('xls_file',  
                         type=werkzeug.datastructures.FileStorage, 
                         location='files', 
                         required=True, 
                         help='XLS file')

Then add a new resource to your api namespace

# api.py
import …
import parsers

@api.route('/upload/')
class my_file_upload(Resource):
    @api.expect(parsers.file_upload)
    def post(self):
        args = parsers.file_upload.parse_args()
        if args['xls_file'].mimetype == 'application/xls':
            destination = os.path.join(current_app.config.get('DATA_FOLDER'), 'medias/')
            if not os.path.exists(destination):
                os.makedirs(destination)
            xls_file = '%s%s' % (destination, 'custom_file_name.xls')
            args['xls_file'].save(xls_file)
        else:
            abort(404)
        return {'status': 'Done'}

I hope this helps.

k3z
  • 518
  • 4
  • 14
  • 1
    To do it in a restful way I think you should first create a file object so: `POST /api/v1/file {"meta": "some data"}` then you receive file object so: `{"meta": "some data", "created_time": "timestamp", "id": 1}`, then you add the attachment using PUT with the binary of file so: `PUT /api/v1/file/1/attachment` – MichalMazurek Nov 11 '16 at 21:10
  • PUT or POST if you are doing it with simple html form – MichalMazurek Nov 11 '16 at 21:16
  • @samurai I agree that this would usually be the way to go. The problem with this approach, though, is that Flask-RESTPlus doesn't support passing the binary blob as request body directly (nor does Swagger 2.0). Instead one has to resort to using the form data approach k3z suggested in his answer – at least if one wishes to describe the file upload API (and in particular the expected `Content-Type` for requests) using Swagger. – balu May 04 '18 at 16:01