Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

swagger flask restplus, upload a file and take json input together

I am trying to upload a file and well as take an input from the user in json format using Swagger UI. I have written the below code for the same.

upload_parser = api.parser()
upload_parser.add_argument('file', location='files',
                       type=FileStorage, required=True)

type = api.model("tax", {
"tax_form": fields.String()})

@api.route('/extraction')
@api.expect(upload_parser)
class extraction(Resource):
@api.expect(type)
def post(self):

    tax_form= api.payload # json input string
    print(tax_form['tax_form'])
    args = upload_parser.parse_args() # upload a file
    uploaded_file = args['file']
    output = func_extract(uploaded_file,tax_form['tax_form'])
    return output, 201

When i run the above individually for eg, if i only upload a file or only take an input from user, the code works but if i do them together. tax_from returns None value, it does not take what I am inputting as json value via Swagger UI.

like image 793
Aswathi Mohankumar Nambiar Avatar asked Nov 13 '18 14:11

Aswathi Mohankumar Nambiar


2 Answers

I got the issue solved. Used reqparse for inputting the argument. See the code snippet as below

upload_parser = api.parser()
upload_parser.add_argument('file', location='files',
                   type=FileStorage, required=True)

parser = reqparse.RequestParser()
parser.add_argument('tax_form', required = True)

@api.route('/extraction')
@api.expect(upload_parser)

class extraction(Resource):
@api.expect(parser)

def post(self):
    """
    extract the content
    """
    args1 = parser.parse_args()
    tax_form = args1['tax_form']
    print(tax_form)
    args = upload_parser.parse_args()
    uploaded_file = args['file']
    output = func_extract(uploaded_file,tax_form)
    return output, 201
like image 178
Aswathi Mohankumar Nambiar Avatar answered Nov 12 '22 17:11

Aswathi Mohankumar Nambiar


I recommend using list of models and parsers in api.expect with validate=True(if required). This will remove the dependency of defining the expected query parameter (in your case) in the class level as you may have GET/PUT/DELETE API on the same route which may not even need this parameter.

Have modified your code to understand better:

upload_parser = api.parser()
upload_parser.add_argument('file', location='files',
                           type=FileStorage, required=True)

tax_type = api.model("tax", {"tax_form": fields.String()})

@api.route('/extraction')
class extraction(Resource):
    @api.expect(tax_type, upload_parser, validate=True)
    def post(self):
        tax_form= api.payload # json input string
        args = upload_parser.parse_args() # upload a file
        uploaded_file = args['file']
        output = func_extract(uploaded_file,tax_form['tax_form'])
        return output, 201

    # This METHOD is now independent of your POST data expectations
    def get(self):
        output = {} # Some JSON
        return output, 200

Also, please avoid using python reserved keywords like 'type' as variables.

Hope this helps ..!!

like image 2
Sawan Choudhary Avatar answered Nov 12 '22 17:11

Sawan Choudhary