flask-restplus icon indicating copy to clipboard operation
flask-restplus copied to clipboard

upload multiple files via swagger UI.

Open vvasuki opened this issue 6 years ago • 8 comments

Given a parser like the below (from here):

@api.route('/dbs/<string:db_id>/books')
@api.param('db_id', 'Hint: Get one from the JSON object returned by another GET call. ')
class ImageBookList(BookList):

  post_parser = api.parser()
  # The below only results in the ability to upload a single file from the SwaggerUI. TODO: Surpass this limitation.
  post_parser.add_argument('in_files', type=FileStorage, location='files')
  post_parser.add_argument('book_json', location='form', type='string')

  @api.expect(post_parser, validate=True)
  def post(self, db_id):
    ...

the swagger UI (eg here) allows me to only upload a single file. How to get the swagger UI to allow uploading multiple files?

image

vvasuki avatar Jan 20 '18 02:01 vvasuki

As a workaround, why don't you call the REST endpoint multiple times (once for each file)? Also, I don't understand your comment regarding the jsonStr parameter – I mean, obviously you can't accept form data and JSON at the same time: Either the POST request's bodys MIME type is application/json or it is multipart/form-data.

codethief avatar May 04 '18 14:05 codethief

As a workaround, why don't you call the REST endpoint multiple times (once for each file)?

My service is to accept/ reject multiple files simultaneously - as an atomic transaction - so this wouldn't suffice.

Also, I don't understand your comment regarding the jsonStr parameter – I mean, obviously you can't accept form data and JSON at the same time: Either the POST request's bodys MIME type is application/json or it is multipart/form-data.

I suppose you were talking about the following commented code?

  # post_parser.add_argument('jsonStr', location='json') would lead to an error - "flask_restplus.errors.SpecsError: Can't use formData and body at the same time"

I just removed it from my initial post to avoid misunderstanding.

vvasuki avatar May 04 '18 17:05 vvasuki

@vvasuki Yep, I was referring to the comment.

My service is to accept/ reject multiple files simultaneously - as an atomic transaction - so this wouldn't suffice.

I see, that makes sense. Having taken another look at your code, though, I'm wondering why you are only adding one argument to the parser that's of type=FileStorage. Why don't you add multiple ones (as would be required to upload multiple files as far as I understand the docs)?

codethief avatar May 09 '18 15:05 codethief

Swagger UI is not supporting multiple uploads. Try it in post man.

Madhuv2 avatar Oct 11 '18 21:10 Madhuv2

If you need to upload many files, try this:

import werkzeug
create_person = reqparse.RequestParser()
create_person.add_argument("images", 
                            type=werkzeug.datastructures.FileStorage,
                            location="files",
                            required=True,
                            help="Person images",
                            action='append')

It work for me 😍

BostonKenne avatar Sep 10 '19 14:09 BostonKenne

The above solution is great until you need to add additional args (such as in the header). This is what I ended up using:

parser = reqparse.RequestParser()
parser.add_argument(
    'File1', type=FileStorage, location='files',
    help=parser_help1, required=True)
parser.add_argument(
    'File2', type=FileStorage, location='files',
    help=parser_help1, required=True)
parser.add_argument(
    'HeaderArg1', type=str, location='headers',
    help=parser_help2, required=True)
parser.add_argument(
    'HeaderArg2', type=str, location='headers',
    help=parser_help3, required=True)

rootVIII avatar Jan 07 '20 21:01 rootVIII

@BostonKenne @rootVIII How do you get the actual files from parser? args = self.parser.parse_args() doesnt work for me.

TusharNimbhorkar avatar May 10 '21 23:05 TusharNimbhorkar

You might need to look up werkzeug file storage. You can just parse it in the view/route/endpoint via request.files. Might be good to look here: https://tedboy.github.io/flask/generated/generated/werkzeug.FileStorage.html and https://flask.palletsprojects.com/en/2.0.x/api/#flask.Request.files

You can actually parse the file content from the request without even having to save to disk if you don't want to.

rootVIII avatar May 16 '21 18:05 rootVIII