12

I have written a simple REST-ful web server in python with flask following steps in this tutorial; but I've got a problem calling POST request. The code is:

@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
    if not request.json or not 'title' in request.json:
        abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task}), 201

I send a POST request using curl as the example in the above mentioned page:

curl -i -H "Content-Type: application/json" -X POST -d '{"title":"Read a book"}' http://127.0.0.1:5000/todo/api/v1.0/tasks

But I get this error in response:

HTTP/1.0 400 BAD REQUEST
Content-Type: text/html
Content-Length: 187
Server: Werkzeug/0.11.10 Python/2.7.9
Date: Mon, 30 May 2016 09:05:52 GMT

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)</p>

I've tried to debug and I found out in the get_json method, the passed argument has been translated to '\\'{title:Read a book}\\'' as data and request_charset is None; but I have no idea for a solution. Any help?

EDIT 1:

I have tried @domoarrigato's answer and implemented the create_task method as the following:

@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
    try:
        blob = request.get_json(force=True)
    except:
        abort(400)
    if not 'title' in blob:
        abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': blob['title'],
        'description': blob.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task}), 201

But this time I got the following error after calling POST via curl:

HTTP/1.0 400 BAD REQUEST
Content-Type: text/html
Content-Length: 192
Server: Werkzeug/0.11.10 Python/2.7.9
Date: Mon, 30 May 2016 10:56:47 GMT

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>The browser (or proxy) sent a request that this server could not understand.</p>

EDIT 2:

To clarify, I should mention that I'm working on a 64-bit version of Microsoft Windows 7 with Python version 2.7 and the latest version of Flask.

7 Answers 7

27

This works in Windows 7 64:

curl -i -H "Content-Type: application/json" -X POST -d "{\"title\":\"Read a book\"}" http://localhost:5000/todo/api/v1.0/tasks

Back slashes and double quotes.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you @dmitriy-bogdanov This worked for me in Windows 10 - 64bit version...
Using powershell you will need to use ` to escape the double quote
4

I Managed to get it working using Anaconda cmd window, python3, using backslashes and double quotes around the whole expression! Works:

curl "localhost:5000/txion" -H "Content-Type: application/json" -d "{\"from\": \"akjflw\" ,\"to\" : \"fjlakdj\", \"amount\": 4}"

Does not work:

curl "localhost:5000/txion" -H "Content-Type: application/json" -d '{\"from\": \"akjflw\" ,\"`to\" : \"fjlakdj\", \"amount\": 4}'

Comments

3

If you are using windows your json string in your request should look like:

"{\"title\":\"Read a boo\"}"

I've got the same problem and it helped.

1 Comment

This is not a valid answer !
1

Instead of using the request.json property, try using request.get_json(force=True) I would rewrite it:

@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
    try:
        blob = request.get_json(force=True)
    except:
        abort(400)
    if not 'title' in blob:
        abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': blob['title'],
        'description': blob.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task})

1 Comment

updated my answer - removed the , 201 in the return statement - i think you just need to return the serialized json.
1

If you're using powershell to use CURL, you need to use curl.exe specifically (not curl) add the 'dumb parsing' tag --%.

Then all you have to do is double quote it and escape the double quotes inside the JSON. Single quoting the outside doesn't appear to work.

"{\"title\":\"Read a book\"}"

Comments

0

Just put " instead of ' around the JSON string, and \ before any " inside the JSON string.

Comments

-1
from flask import Flask, request, abort, jsonify

app = Flask(__name__)
tasks = [{'id': 0}]

@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
    if not request.json or 'title' not in request.json:
        abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'done': False
    }
    tasks.append(task)
    response = {"task": task}
    return jsonify(response), 201

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

curl:

curl -i -H "Content-Type: application/json" -X POST -d '{"title":"Read a book"}' http://127.0.0.1:5000/todo/api/v1.0/tasks

OP:

{
  "task": {
    "description": "", 
    "done": false, 
    "id": 1, 
    "title": "Read a book"
  }
}

5 Comments

Your solution is totally identical to mine!
yea that's what! I was not able to reproduce the error!!
@Amit Karnik This error comes when u run in windows because is is not able to understand that for what purpose that meta char ` " ` it has to use. So use ` \" ` instead of ` " ` will work perfectly.
everyone knows it... have anything diff??
Tried this in linux running curl 7.68.0, does not work, still get same error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.