What error to raise with wrong post request body? - python

I am new to Django and have an endpoint that accepts post requests. The endpoint expects a specific set of keys in the post request body. What type of Exception should I raise if they don't provide the right keys? ValueError? Thanks!

You should return a HttpResponseBadRequest response and include a helpful message with the invalid data. This returns a 400 response which is used to indicate issues with request data
If you are creating rest endpoints with Django it is worth using a library like https://www.django-rest-framework.org/ as it can simplify their creation and handle a lot of the leg work around validation, serialisation and reponses

Related

Django rest framework, serializer invalid when sent through Angular

I'm having a problem where when I make a post request from my Angular application served through Django I get invalid serializers, even if the output is correct.
I console log the sent data:
{"email":"example#gmail.com","username":"example","password":"plaintextforthisexample","confirm_password":"plaintextforthisexample"}
Which gives me the response Bad Request (which I have set to happen when serializer.is_valid() is false).
However, if I copy and paste what's in the console log into the browsable API under raw data it accepts it and creates a user.
I can successfully send get-requests to the same API and get the data back, and the permissions for getting and posts are the same, although that would result in another type of error.
The content type is correct as well, when not I get a 415. If the URL is wrong I get a 500. And I can see on the Django server log that post requests are coming in.
Could it be because I'm running it from an angular template and not a Django one?
EDIT:
Picture of the console:
Issue 1: The console logged output that worked in Django was not the one actually being sent, resulting in a JSONParse error.
It looked like something like this
function(formobject){
let payload = JSON.stringify(formobject)
console.log(payload)
return formobject
Issue 2: Now Django gives my my custom response on arrival:
Status:'Bad Request'
Message:'Data does not fullfill requirements for creating a user'
And does not allow me to copy-paste the JSON-output from the console into the API raw data-form.
Solved by not using the same password I had been using for about 15 tries. Seems Django detects common passwords, has not been fully tested.

request.data in DRF vs request.body in Django

Django REST framework introduces a Request object that extends the regular HttpRequest, this new object type has request.data to access JSON data for 'POST', 'PUT' and 'PATCH' requests.
However, I can get the same data by accessing request.body parameter which was part of original Django HttpRequest type object.
One difference which I see is that request.data can be accessed only one time. This restriction doesnt apply to request.body.
My question is what are the differences between the two. What is preferred and what is the reason DRF provides an alternative way of doing same thing when There should be one-- and preferably only one --obvious way to do it.
UPDATE: Limiting the usecase where body is always of type JSON. Never XML/ image or conventional form data. What are pros/cons of each?
You should use request.data. It's more flexible, covers more use cases and it can be accessed as many times as needed. Quoting the docs:
Aboout request.data
REST framework introduces a Request object that extends the regular
HttpRequest, and provides more flexible request parsing. The core
functionality of the Request object is the request.data attribute,
which is similar to request.POST, but more useful for working with Web
APIs.
request.POST # Only handles form data. Only works for 'POST' method.
request.data # Handles arbitrary data. Works for 'POST', 'PUT' and
'PATCH' methods.
About request.body
The raw HTTP request body as a byte string. This is useful for
processing data in different ways than conventional HTML forms: binary
images, XML payload etc. For processing conventional form data, use
HttpRequest.POST.
So unless you want to handle binary images or XML payload, never use request.body, it'll only be a simple string containing, well, the body of the request. Always use request.data which'll be the fully parsed body (i.e. a Python dict) which is much more convenient to handle.
In rest_framework.request.Request
request.body is bytes, which is always available, thus there is no limit in usage
request.data is a "property" method and can raise an exception,
but it gives you parsed data, which are more convenient
However, the world is not perfect and here is a case when request.body win
Consider this example:
If client send:
content-type: text/plain
and your REST's endpoint doesn't accept text/plain
your server will return 415 Unsupported Media Type
if you access request.data
But what if you know that json.loads(request.body) is correct json.
So you want to use that and only request.body allow that.
FYI: A described example is a message of AWS SNS notification sent by AWS to HTTP endpoint. AWS SNS works as a client here and of course, this case is a bug in their SNS.
Another example of benefits from request.body is a case when you have own custom parsing and you use own MIME format.

Python-Eve: formatting GET response to HTTP 200

I have Python-Eve running with MongoDB on a Ubuntu VM. I am trying to write an api to handle POST requests from an Iridium RockBLOCK modem. I have tested the API with Chrome Postman, and am able to successfully POST data.
When I try and send messages from my RockBLOCK I get 422 error messages on the VM. I am pretty sure this is because the RockBLOCK is not able to handle XML or JSON data, and is set up to simply look for an HTTP 200 response.
So how would I setup eve to respond with solely HTTP 200 when the POST request is received?
API Format taken from RockBLOCK Web Services Guide.
The 422 is returned from Eve when a validation error occurs. I would look into your request payload and make sure it adheres to validation rules. A typical example of a response like this would be when you have a unique rule for a field, and a POST comes in with an already used value for that field.
So how would I setup eve to respond with solely HTTP 200 when the POST request is received?
Right now you can disable either JSON or XML responses by respectively setting JSON = False or XML = False, but not both. Since Eve is a Flask application you could look into changing the response on the flight but again, given the error you are getting I don't think that is the problem you are facing right now.

Django Rest API POST issues

I'm trying to build a very simple REST API in Django 1.8 with Django REST Framework in Visual Studio, in which I want to have a single service method to process a JSON, but I can't seem to make a POST:
I'm trying to send this simple JSON through Postman, just as a test:
{
"foo":"bar"
}
with the header:
Content-Type: application/json
Here's my method:
#csrf_exempt
#api_view(['POST'])
def test(request):
data = request.data
return HttpResponse(status=200)
But my problem is that request.data is empty. And if instead I try to access request.body, I get
You cannot access body after reading from request's data stream.
Any ideas what could be the issue here?
Figured this out somewhat, it seems to be an issue with Visual Studio while in debug mode. If I try to access the request while debugging before calling any Python function on it (such as a simple print, or passing in to a function to parse it), it shows up as an empty QueryDict, otherwise it shows up fine.
Just a guess: maybe the issue is in Postman?
Try to send POST-request without headers, but with raw JSON (not form-data):
This may help Where's my JSON data in my incoming Django request?
Outside of this, make sure the content-type and accept-type are set properly. What is the raw response in Postman? Is the security setup properly?
I have the same problem when using POSTMAN.
Solved and Credit goes to https://stackoverflow.com/a/31977373/764592
Quoted Answer:
Request payload is not converted into JSON format.
I am passing my data in Body as x-www-form-urlencoded
You can fix it by using Content-Type as application/x-www-form-urlencoded in request header.

Flask: Getting request parameters based on Content-Type header

What is the proper way to deal with the request body depending on the Content-Type header of the request?
I need to implement a RESTful service that supports XML, JSON and form encoded request parameters, but I can't seem to find a clean way of extracting the request parameters.
Is this something that I should use a middleware for? Do I need to extend the Request object?
I haven't found any packages that do this, and it seems like a pretty common task for creating RESTful services in flask.
You probably meant Accept header, as Content-Type is used for response. There are three choices here:
Build it youself as described in Handling Accept Headers snippet.
Use Flask-RESTful extension (consult Content Negotiation part in the docs).
Use Flask-Pushrod extension which is specifically built to handle this case.
You could use #app.before_request as illustrated here. Once you've done your thing normalizing the request params, you can save them to g, something like this:
from flask import g
from flask import request
...
#app.before_request
def before_request():
# normalize params based on Content-Type
g.params = normalized_params

Categories

Resources