1

I am using this documentation: from FLASK Restful

from flask import Flask, request
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

todos = {}

class TodoSimple(Resource):
    def get(self, todo_id):
        return {todo_id: todos[todo_id]}

    def put(self, todo_id):
        todos[todo_id] = request.form['data']
        return {todo_id: todos[todo_id]}

api.add_resource(TodoSimple, '/<string:todo_id>')

if __name__ == '__main__':
    app.run(debug=True)

In order to add the new todo, they call the following command on python:

from requests import put, get
put('http://localhost:5000/todo1', data={'data': 'Remember the milk'}).json()

The data comes from the json object {'data': '.....} and it retrieved here: request.form['data']

I want to replace 'Remember the milk' with my data2 object:

data2 = {'ALTNUM':'noalt', 'CUSTTYPE': 'O',
'LASTNAME':'lnamedata2', 'FIRSTNAME':'fndata2', 'ADDR':'1254 data 2 address',
'ADDR2':'apt 3', 'CITY':'los angeles', 
'COUNTY':'011', 'STATE':'CA', 
'ZIPCODE':'90293', 'COUNTRY':'001', 
'ADDR_TYPE':'O','PHONE':'4254658029',
'PHONE2':'3442567777', 
'EMAIL':'test2@test2.com'}

and call: print put('http://localhost:5000/newcustomer', data={'data':data2}).json()

MY API resource:

class New_Customer(Resource):
    def put(self):
        q = PHQuery()
        data = request.form['data']
        print(data)
        return data

I get the following errors when calling these:

print put('http://localhost:5000/newcustomer', data=data2).json()
print put('http://localhost:5000/newcustomer', data={'data':data2}).json()
print put('http://localhost:5000/newcustomer', data=data2).json()
print put('http://localhost:5000/newcustomer', data=data2)



{u'message': u'The browser (or proxy) sent a request that this server could not understand.'}
CUSTTYPE
{u'message': u'The browser (or proxy) sent a request that this server could not understand.'}
<Response [400]>

What am I doing wrong? @foslock should it be data = request.json['data'] ? since it is an object and not form data?

  • The `400` response is because you are sending a payload with no `data` key. When you attempt to get it via `request.form['data']` I believe Flask-RESTful will automatically respond with that error since that key (`data`) does not exist in the payload. – foslock Jul 05 '17 at 23:52

1 Answers1

1

Returning JSON, not str

It looks like your API routes are returning raw string casted versions of the resource objects. You instead want to return them as JSON, which flask can do for you with the jsonify method.

import flask

class New_Customer(Resource):
    def put(self):
        q = PHQuery()
        data = request.get_json()
        new_cust = q.create_cust(data)
        return flask.jsonify(new_cust)

Notice how in Python, the string representation of a native dictionary is not exactly equivalent to the JSON version:

>>> dct = {'Hey': 'some value'}
>>> print(dct)
{'Hey': 'some value'}
>>> print(json.dumps(dct))
{"Hey": "some value"}

Sending JSON with PUT/POST

When using the requests library to send a PUT/POST request, you are by default sending the body of the request in a form-encoded (application/x-www-form-urlencoded to be specific) format, which is explained here. This format is not great for nested structured data like what you are attempting to send. Instead, you can send the data JSON encoded (application/json) using the json keyword argument.

requests.put(url, json=data2)

Side note: If you are attempting to create a new customer, you may want to use POST instead as it may be considered more RESTful, as PUTs are generally for updating an existing resource, but this is up to you.

Pulling values from PUT/POST Data

Since we are sending the body of the request as JSON now, we need to deserialize it as such in the API server. You can see this happening above in the following line:

data = request.get_json()

You can refer to this answer for more information about properly pulling data out of a HTTP request in Flask.

foslock
  • 3,029
  • 2
  • 18
  • 22
  • I tired that, in fact I even commented out the return line all together. I am still getting the same error. It seems like the problem is here put('http://localhost:5000/newcustomer', data={'data':data2}) I HAVE UPDATED THE CODE: –  Jul 05 '17 at 22:28
  • @eleazarolivera When you call `.json()` on the requests `Response` object, it attempts to convert `response.content` into JSON, which would fail if the response was not valid JSON. Your server is likely returning an error string, in a 500 response, due to the `put` method signature. – foslock Jul 05 '17 at 22:32
  • the server is responding 500 –  Jul 05 '17 at 22:39
  • >>> put('http://localhost:5000/newcustomer', data={'data':data2}) returns : AND >>> put('http://localhost:5000/newcustomer', data={'data':data2}).json() returns: return self.scan_once(s, idx=_w(s, idx).end()) simplejson.scanner.JSONDecodeError: Expecting value: line 1 column 1 (char 0) >>> –  Jul 05 '17 at 22:41
  • @eleazarolivera See my updates about the `put` method on your `New_Customer` resource class. – foslock Jul 05 '17 at 22:42
  • I am getting the put command to work, I cannot seem to get the entire data2 to pass. It is printing CUSTTYPE which is one of my fields in the DB. –  Jul 05 '17 at 23:45
  • Here is the api.py `class New_Customer(Resource): def put(self): q = PHQuery() data = request.form['data'] print(data) return data` and the request `print put('http://localhost:5000/newcustomer', json=data2).json()` I know the syntax will not work untill i change for['data'] to retrive the correct data2. I am not sure how to write it. ] –  Jul 05 '17 at 23:58
  • I have updated the question. I am going to look into post instead. I used put since i was just following the example. How would I write the method to retrive the data2 object ? once I can obtain this in the API, I know how to send it to my DB with my Query object. But I first want to at least print the data2 in the api.py server side file to know that it is being retrieved in here: `data = request.form['data'] print(data)` –  Jul 06 '17 at 00:28
  • There are many resources for Flask Restful, but they dont show the call that would be executed on the server sending the info. –  Jul 06 '17 at 00:30
  • @eleazarolivera I have updated the answer, it should be enough to get you going. – foslock Jul 06 '17 at 18:17
  • Thank you. The data on the requesting server will be in a form, but it is good to be able to test it out this way initially. –  Jul 06 '17 at 21:10