Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse the POST argument to a REST service?

It seems I have another JSON problem, this time when posting to the REST service. I am using Flask-Restful.

api.add_resource(Records, '/rest/records/<string:email>/<string:password>/<string:last_sync_date>')

parser = reqparse.RequestParser()
parser.add_argument('record_date', type=str)
parser.add_argument('records', type=str)
parser.add_argument('rating', type=str)
parser.add_argument('notes', type=str)

class Records(Resource):
    def post(self, email, password, last_sync_date):
        args = parser.parse_args()
        records = args['records'] # 'records' = None, but why? 
        return records, 201

Unit test:

resource_fields = {
            'record_date': fields.String,
            'rating': fields.Integer,
            'notes': fields.String,
            'last_updated': fields.DateTime,
        }
records = {"records":[]}
records["records"].append(marshal(record1, resource_fields))
    rv = self.app.post('/rest/records/{0}/{1}/{2}'.format(email, password, sync_date), data=json.dumps(records))

json.dumps(records) is:

str: {"records": [{"rating": 1, "notes": null, "last_updated": "Tue, 15 Oct 2013 15:52:44 -0000", "record_date": "2013-10-15 15:52:44.746815"}]}

Why is args['records'] None, where I am clearly sending it over the wire?

UPDATE:

Strange part is when I send a single object, its all dandy. So strange:

record = dict(record_date=record1.record_date, rating=record1.rating, notes=record1.notes, last_updated=record1.last_updated)

rv = self.app.post('/rest/records/{0}/{1}/{2}'.format(email, password, sync_date), data=record)

args:

{'records': None, 'notes': None, 'task': None, 'record_date': '2013-10-15 16:48:40.662744', 'rating': '1'}
like image 318
Houman Avatar asked Oct 15 '13 14:10

Houman


People also ask

How do I send a post request to Rest API?

To post JSON to a REST API endpoint, you must send an HTTP POST request to the REST API server and provide JSON data in the body of the POST message. You also need to specify the data type in the body of the POST message using the Content-Type: application/json request header.

What is Reqparse in Flask-RESTful?

With resources defined and everything connected with Blueprints, it's time to handle incoming arguments. Flask-RESTful provides a solid tool known as Reqparse for specifying and validating submitted data.


1 Answers

I ended up raising this as an issue on flask-resful github and got this solution, which works for me. Credit goes to Doug Black.

reqparse doesn't really know how to handle JSON. To deal with JSON posts, you'll want to use the flask.request.json dict.

Here's an updated example for what you probably want:

from flask import Flask, request
from flask.ext import restful

class Records(restful.Resource):
    def post(self, email, password, last_sync_date):
        records = request.json['records']
        return records, 201

app = Flask(__name__)
api = restful.Api(app)
api.add_resource(
    Records, 
    '/rest/records/<string:email>/<string:password>/<string:last_sync_date>'
)

The docs on request.json are here.

You'll need to make sure you post with the content type header set to application/json so flask knows to populate the json dictionary.

self.app.post(
    '/rest/records/{0}/{1}/{2}'.format(email, password, sync_date), 
    data=json.dumps(records), 
    headers={'Content-Type': 'application/json'
)
like image 64
Houman Avatar answered Nov 12 '22 08:11

Houman