6

I'm writing an application using django framework and was thinking about writing something like a rest controller, cos keeping the exception handling logic in one place seems like a good idea. I don't know what would be the right way to do this, but I came up with writing a decorator that comprises a bunch of exceptions that may well be thrown by various methods and thus, that decorator is used on each of them.

def exception_handler(function):
    def wrapper(*args, **kwargs):
        try:
            return function(*args, **kwargs)
        except Error1 as error:
            return Response(
                {"Error": str(error)},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Error2 as error:
            return Response(
                {"Error": str(error)},
                status=status.HTTP_404_NOT_FOUND
            )
        except Error3 as error:
            return Response(
                {"Error": str(error)},
                status=status.HTTP_503_SERVICE_UNAVAILABLE
            )
     return wrapper

Where Error1, Error2 and Error3 are just some abstract errors. In my applications there's more of them indeed.

Simple controller (aka django view) may look something like this:

class DeviceView(viewsets.ModelViewSet):
    lookup_field = 'id'
    serializer_class = DeviceSerializer

    @exception_handler
    def create(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save(data=request.data)
        return Response(status=status.HTTP_200_OK)

So basically if any of the exceptions is thrown it will be handled in the appropriate way. One of the problems that I see here is that if it's not me who raises an exception with a desired message:

if some_condition:
    raise SomeException("Something happened")

it will be a default one and oftentimes I would prefer to alter it. So I start feeling somewhat uncomfortable about controlling what message should be shown to the client. The best that I could come up with right now is this:

try:
    this_function_throws_someexception(args)
except SomeException:
    raise SomeException("Here is the message I want to show to the client")

Which means I have to re-raise the exception thrown with the message I'd want it to be raised. My first question is "Is this the best way to deal with it?". And the second question is : "Is the whole approach to exception handling good?"

1 Answer 1

2

The recommended approach used by books and professionals is making a mixin and a double inheritance.

DOCUMENTATION: Using Mixin with CBV

When using DOUBLE INHERITANCE everything written on the Mixin will overlap/override and merge with the first import.

class A:  
    function gives a  
    no var defined  
    exception 1

class Bmixin:  
    function gives b
    var is b

class X(A, Bmixin):
    function gives b
    exception 1
    var is b (first was a but then was overriden by the Mixin because the 
    function is named equally)

As you can see class X has everything from both classes and has an override on the similar defined stuff on both classes.

Typically you define a basic ErrorHandling Mixin and a few more specific ones and you stack as many Mixins as you are required on the final View.

class A(ViewStuff, ErrorBasicMixin, ErrorMoreSpecificMixin):

First you put al the stuff on a class ended up in Mixin on the name (just a convention but a quite useful one) which includes the extra stuff you would want to add to your class, in this case all the Exceptions.

Such as

class ErrorHandlingMixing():   #No need of inheritance inside brackets "()"
    #code

Most people make a different .py file for the mixins, such as mixins.py

Then import it on your views:

from .mixins import ErrorHandlingMixing

And do a double inheritance on creating your view class

class User (AmbstractBaseUser, PermissionsMixin):
    #code

There are also a lot of already created mixins for this such as PermissionsMixin

from django.contrib.auth.models import PermissionsMixin

I will put you an example of a mixins.py from github

I would say the decorator approach is more oriented at deciding wether or not the view should be processed, such as with permissions. I assume you could try to do this with decorators but Mixins seems cleaner, less repetitive and is the default approach by professionals.

Kind regards

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

Comments

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.