Django Rest Framework fails to handle malformed JSON - python

I have the following function in Django Rest Framework:
#api_view(['GET', 'PUT'])
#permission_classes((permissions.IsAuthenticated,))
def TestView(request, app_id):
return Response({})
It should always return a json response with the empty object, right? Wrong. If I PUT data at this url with media type application/json, and send it malformed json, then Django barfs out a 500 response:
ParseError at /api/v1/test-url
No exception message supplied
I feel like DRF should either raise an exception that I can catch, or send out a 400 error. In fact, the docs even state:
The wrappers also provide behaviour such as returning 405 Method Not
Allowed responses when appropriate, and handling any ParseError
exception that occurs when accessing request.DATA with malformed
input.
So why is my application spitting out a 500 error?

You can configure a custom exception handler and handle the ParseError in there.

Related

Django - Returning full exception trace to front-end on a 400

So just for closed beta and internal testing purposes I'm trying to return the exception with the 400 error in my Django server. Here is an example below of how I am doing this in Django code. I have a partner working on the front-end and they said they can't get the error out of the 400 response. I assumed it'd be in like response.body['error']. How can I send back a 400 with the full error trace in a way that can be pulled out by the front-end?
except Exception as e:
return Response(dict(error=str(e),
user_message=error_message_generic),
status=status.HTTP_400_BAD_REQUEST)
The most common approach is this:
from django.http import JsonResponse, HttpResponseBadRequest
return HttpResponseBadRequest(JsonResponse({
"error": "Malformed request",
# Any other fields you'd want
}))
See more at official docs.
If you are interested on returning specifically a traceback of your back-end exception, you can go this way:
from django.http import JsonResponse, HttpResponseBadRequest
import traceback
...
except Exception as e:
return HttpResponseBadRequest(JsonResponse({
"error": "Malformed request",
"traceback": traceback.format_exc()
}))
traceback.format_exc()
But it's not the best way to do it in all cases. If you are sure, that exception is related to user's input, then traceback wouldn't be so helpful for user. You should better use Serializer, whose validation would be much better. If you're just delivering information about unknown error I'd advise to use HttpResponseServerError and log your exceptions anywhere, to sentry, for example.

Return an HTTP fail (e.g. 500) response with JSON body from flask?

As of flask 1.1.x, it is easy to return a JSON response body along with an HTTP success code, such as
return {"success": 1, "message": "You did it!"}, 200
However, returning an HTTP failure status the same way
return {"success": 0, "message": "You screwed up."}, 400
only seems to return a response header and message, (e.g. HTTP/1.0 INVALID REQUEST)
The Content-type header (correctly) says application/json, but, the body is empty. This happens for any non-2xx class status code.
Flask documentation implies I should be able to do this, but, nothing I've tried seems to work. This includes creating specialized error handlers like
#app.errorhandler(400)
def custom400(error):
return jsonify({'message': error})
and then calling abort(400, 'my error message'), which doesn't work since the error argument to the handler isn't the string passed to abort, but, is always an error object of whatever type the HTTP error is (e.g. 410 -> <GONE Gone>.
Is this "normal" HTTP response behaviour, or is flask doing something weird?
It turns out this is more PEBKAC than anything else. I had set a breakpoint inside my $.ajax.error handler, looking at the returned response in the browser (chrome) debug window when the breakpoint fired.
But,the body of the response isn't made available to the debug window until AFTER this handler exists. Once I continued execution of the error handler, the JSON response body is came through as expected.

Difference between Flask abort() or returning a status

What is the difference between abort(400) and returning a response with a 400 status? Is using return bad form for errors?
abort(400, "some error message")
# or
return {'message': "some error message"}, 400
abort raises an error, which an error handler will convert to a response. return returns a response, error handlers don't trigger. It's up to how you want your application to flow.
abort is a wrapper that raises HTTPException classes. Calling abort is the same as raising an exception and Flask will handle both the same way. Returning is not the same as raising an exception and will be handled differently.

django - handler404 vs handler500

I am now a little bit confused.
There are handler404 and handler500 in Django which I can override. I thought, I can do this:
try:
mymodel = MyModel.objects.get(id=someid)
except MyModel.DoesNotExist:
raise Http404
But I would love to know what really caused this 404 - Server Error or just a wrong URL..
how would this be possible? can I have infos about 500 error inside handler404?
in case of 500, handler500 does have a RequestContext and things like {{STATIC_URL}} will stop workingin 500.html. thats why i thought, i will raise 404 instead and email the admin inside 404 handler about error. does this make sense?
The bottom line is this:
In order to generate/cause/raise a 500, you have to request a valid URL.
Its quite simple - the 404 will only be raised if there was no 500 error, because the 500 error would not prevent the link from being valid.
So if its 404, there is no chance for it to also raise a 500; because without you requesting a valid URL, no server side code is run; this thus cannot trigger a 500.
They are mutually exclusive.
In your particular case, here is what happens:
You request /foo/bar/1
This URL is mapped using the url patterns to a view, if it matches - that's it, you have no longer a chance to raise a 404.
The request is passed to the handler - now, at this stage, the request pipeline cannot generate a 404.
There was an error in your view code - now one of two things can happen:
You anticipate this error with a try/except, and then you can raise whatever
exception you like. If this exception also returns a response, then whatever
that response is - that is the error code you are sending back in your reply to the client. So, when you raise Http404, it will return a response, with 404 error code. You can happily return any other response and error code combination.
An error occurs that is not caught by your code, or your code does not return a proper response. In this case, the default exception handler for django will return a response and raise 500. This is the normal/default case.
As you can see from the flow, in any case, to return a 500 response, the URL has to be valid.

urllib ignore authentication requests

I'm having little trouble creating a script working with URLs. I'm using urllib.urlopen() to get content of desired URL. But some of these URLs requires authentication. And urlopen prompts me to type in my username and then password.
What I need is to ignore every URL that'll require authentication, just easily skip it and continue, is there a way to do this?
I was wondering about catching HTTPError exception, but in fact, exception is handled by urlopen() method, so it's not working.
Thanks for every reply.
You are right about the urllib2.HTTPError exception:
exception urllib2.HTTPError
Though being an exception (a subclass of URLError), an HTTPError can also function as a non-exceptional file-like return value (the same thing that urlopen() returns). This is useful when handling exotic HTTP errors, such as requests for authentication.
code
An HTTP status code as defined in RFC 2616. This numeric value corresponds to a value found in the dictionary of codes as found in BaseHTTPServer.BaseHTTPRequestHandler.responses.
The code attribute of the exception can be used to verify that authentication is required - code 401.
>>> try:
... conn = urllib2.urlopen('http://www.example.com/admin')
... # read conn and process data
... except urllib2.HTTPError, x:
... print 'Ignoring', x.code
...
Ignoring 401
>>>

Categories

Resources