Error Management
Ninja automatically catches the typical exceptions raised by views and turns them into error objects to be returned by the view. In this lesson, you’ll learn how to define your own exceptions and override the defaults provided by Ninja.
00:00 In the previous lesson, I showed you how to secure Castle Black by implementing authentication. In this lesson, I’ll show you how Ninja handles errors and what you can do to augment it.
00:12 The good news is Ninja tells you a fair amount about what went wrong. The bad news is it might not tell you where you expect. At least, it wasn’t where I expected the first time I wrote an API with this library.
00:25 The other bit of bad news is decorators can be a bit challenging to debug. This isn’t Ninja’s fault. Their choice of using decorators makes it simpler to write your code, but due to how decorators are called, you often can’t just put a breakpoint on them.
00:40 This isn’t a problem if things are running smoothly, but there are days where smoothly feels very far away. Let’s go look at some errors. No new apps this time. I’m just going to hit our existing ones.
00:54 I’ve started the server on the top window, and now on the bottom, I’m going to look for a wedding gift.
01:05
I’m sure it’s some sort of sin to mix mythologies like this, but I suspect Mr. Adams would just find it funny. Anyhow, no gift with ID 42
, so you get a nice little error in response.
01:17 Now, you may recall earlier I said this might not be where you expected. If you’re writing a single-page application, this is buried in the response from the server, which typically means you have to look in your JavaScript console or know enough to add some debug on the client side.
01:33 There are only two things I don’t like about Ninja. The first I mentioned before—them breaking from the typical paths-ending-in-slashes practice—and this is the second one.
01:42 It would be nice for more of the info that shows in the response to also be in the console. You get the 404, but if you’ve got a complex view, you may not be sure where that’s happening inside the view.
01:54 This can be even worse if you are making the mistake of using the wrong HTTP operation. There isn’t an easy way to realize that. Don’t get me wrong. This isn’t a show-stopper, by any means.
02:07 I was just expecting a bit more info in the server console. Now that I know otherwise, it’s just a matter of looking in the right place. Let’s try another call.
02:26
Same kind of challenge here. Nice info in the response telling me I’m missing a field, but the server console has a very generic Unprocessable Entity
.
02:36 Now let’s try the security stuff.
02:42 You’ve seen this one before.
02:50 And if I pass a bad key, I get the same message. I kind of expect the message to be the same on the client side, as you don’t want to give info on why they were denied.
03:00 That’s a security problem on the server side though, which means the debug log. It would be nice to differentiate between the two causes. The first case is missing a cookie, whereas the second has the right header but the wrong password. This is a bit of a rougher edge, but now that you know where to look for it, it isn’t too bad.
03:19 You can customize how things are handled, so if you really wanted to improve on it, you can. Let’s go talk about that. Most of the errors you’ve seen so far are actually exceptions.
03:32
Ninja is catching and handling the standard Django exceptions and then running code to return a response. You can take advantage of this by using Ninja’s HTTPError
exception, which allows you to raise any kind of HTTP error, explicitly setting the status code. You can also write your own exception handlers or use that same process to override Ninja’s built-in handlers if you prefer. Let’s add a new app and visit the Citadel.
04:03
Ninja provides a general HTTPError
exception inside of its errors module. I’ve used it in this example to raise a 503. Note that I’m creating a third Ninja object, which I’ve named citadel
for this lesson. Inside the conclave
API endpoint, I raise a 503 error by using the HTTPError
exception and setting the status code and corresponding message.
04:35
Inside of the main urls
file, I need to import that citadel
object and register it as a separate path for all of this to work.
04:57
and there you go, a custom HTTPError
.
05:05
You can also define your own exceptions. Here, I’ve created the BookUnavailable
exception. I register a custom exception handler by passing the BookUnavailable
error into the .exception_handler()
method on the citadel
object.
05:23
This method uses the .create_response()
method on the Ninja object to create a new JSON response. I pass in a data dictionary with the message info and explicitly set the status code to 404
.
05:37 The view does nothing but raise this new exception so that I can demo it. Let’s fetch a book.
05:50 And there you go. These aren’t the books you’re looking for. Now there I went and mixed genres again. Something tells me Adams has a better sense of humor than Lucas.
06:05
Using a similar registration mechanism, you can override Ninja’s default handlers. In order to do so, I’ll need the HTTP404
and HTTPResponse
classes from Django’s http
module. Ninja already has something for the 404, but by calling the exception_handler
decorator, I can override it with my own.
06:26
Your custom handler needs to return some sort of response. You can use the .create_response()
method like I did before, or just return a valid HTTPResponse
object.
06:36 These things are all just views, after all. Inside the view itself, if I raise a 404, my new handler will now be called instead of the default. Going to try it out.
06:57 And I’ve been told to take the black. I must have done something naughty. There you go. Pull your t-shirt up to cover part of your face and grab a katana. You’re a Ninja now. The last lesson is next.
07:12 I’ll summarize the course and point you at some further investigation, including features in Ninja that I haven’t covered.
Become a Member to join the conversation.