wi3o
wi3o

Reputation: 1607

POSTMAN: Post method using raw body returns 500

I tried to POST a query in json in postman's raw body like below:

enter image description here

and I got 500 internal error server and HTML results like below

enter image description here

Otherwise, I'm able to POST using form-data and from a script ran from the terminal using the same json format.

I use Django 1.5.12 to serve the API and python 2.7.

Can anyone help?

Upvotes: 0

Views: 2486

Answers (2)

Niel Godfrey P. Ponciano
Niel Godfrey P. Ponciano

Reputation: 10709

If you are using request.POST in your code to access the HTTP POST body values, then take note that as stated in https://www.django-rest-framework.org/tutorial/2-requests-and-responses/

request.POST # Only handles form data. Only works for 'POST' method.

If you would like your view to be able to read HTTP POST body values both from form-data (or x-www-form-urlencoded) and raw (JSON format) at the same time, then you cannot use request.POST alone. You could either:

  1. Read from request.body
  2. Read from request.data (only available if the logic is under rest_framework)

Example

urls.py

path('printpostedvalues/', printpostedvalues_view),

views.py

@csrf_exempt
def printpostedvalues_view(request):
    print("request.body", request.body)

    try:
        print("json.loads(request.body)", json.loads(request.body))
        for k, v in json.loads(request.body).items():
            print("json.loads(request.body)", k, "-->", v)
    except Exception:
        print("request.body's string value is not in the format of JSON key:value pairs")

    print("request.POST", request.POST)
    for k, v in request.POST.items():
        print("request.POST", k, "-->", v)

    return HttpResponse("Printed values in console...")

Perform an HTTP POST http://127.0.0.1:8000/printpostedvalues/ using Postman.

Case 1: form-data

HTTP Body

KEY - VALUE
athlete - LeBron James
status - GOAT!
quote - Strive for greatness

Console Output

request.GET <QueryDict: {}>
request.body b'----------------------------269460357877673035654590\r\nContent-Disposition: form-data; name="athlete"\r\n\r\nLeBron James\r\n----------------------------269460357877673035654590\r\nContent-Disposition: form-data; name="status"\r\n\r\nGOAT!\r\n----------------------------269460357877673035654590\r\nContent-Disposition: form-data; name="quote"\r\n\r\nStrive for greatness\r\n----------------------------269460357877673035654590--\r\n'
request.body's string value is not in the format of JSON key:value pairs
request.POST <QueryDict: {'athlete': ['LeBron James'], 'status': ['GOAT!'], 'quote': ['Strive for greatness']}>
request.POST athlete --> LeBron James
request.POST status --> GOAT!
request.POST quote --> Strive for greatness
[11/Mar/2020 04:57:43] "POST /printpostedvalues/ HTTP/1.1" 200 28

Conclusion:

The request.body contains the HTTP POST information from the form-data but is clearly not in the JSON format and thus cannot be parsed through json.loads(). The request.POST also contains the values.

Case 2: x-www-form-urlencoded

HTTP Body

same as Case 1

Console Output

same as Case 1 except for line 2 - request.body b'athlete=LeBron%20James&status=GOAT%21&quote=Strive%20for%20greatness'

Conclusion:

same as Case 1

Case 3: raw (JSON)

HTTP Body

{
    "athlete" : "LeBron James",
    "status" : "GOAT!",
    "quote" : "Strive for greatness"
}

Console Output

request.GET <QueryDict: {}>
request.body b'{\n    "athlete" : "LeBron James",\n    "status" : "GOAT!",\n    "quote" : "Strive for greatness"\n}'
json.loads(request.body) {'athlete': 'LeBron James', 'status': 'GOAT!', 'quote': 'Strive for greatness'}
json.loads(request.body) athlete --> LeBron James
json.loads(request.body) status --> GOAT!
json.loads(request.body) quote --> Strive for greatness
request.POST <QueryDict: {}>

Conclusion:

The request.body contains the HTTP POST information from the raw JSON data and is in the JSON format and thus possible to be parsed through json.loads(). The request.POST does not contain any values.

SUMMARY

Long story short, do not rely on request.POST if you expect HTTP POST body values to come not just as form-data but also as raw JSON format. If you are using rest_framework for this, your best option is to use request.data because it will be able to catch all information coming from an HTTP POST regardless of format.

Upvotes: 0

Rajan
Rajan

Reputation: 1497

When you submit form data the content-type header will be

Content-Type: multipart/form-data

and in your Django view, you will do something like below to read the posted data:

name = request.POST.get('name')

However, when you post data using the way you did now with the postman, the header will be:

Content-Type: application/json

and to grab this json data, you can do something like:

import json

mydata = json.loads(request.body)
name  = mydata.get('name')

Status 500, must be because you have not handled the case for json request in your view.

Upvotes: 2

Related Questions