-3

I am writing an API function using DRF where I want the API execution to stop if it fails in any of the steps and return an appropriate response. So I created a custom exception which takes an error code, and an error message like below.

class CustomException(Exception):
def __init__(self, status, msg):
    self.status = status
    self.message = msg
    super().__init__(self.message + ': ' + str(self.status))

And I came up with the below code structure for the API function,

def place_order(request):
    err_msg = 'Problem in placing order. Please contact us'
    try:
        response = is_cart_empty()
        if response.status == 0:
            err_msg = 'Cart cannot be empty'
            raise CustomException(0, err_msg)

        # Do something...

        response = is_valid_user()
        if response.status == 0:
                err_msg = 'User is not valid'
                raise CustomException(0, err_msg)

        # Do something...

        response = is_product_available()
        if response.status == 0:
            err_msg = 'Product out of stock'
            raise CustomException(0, err_msg)

        # Do something...

        response_data = {
            'status': 1,
            'order_id': '1235'
        }
    except CustomException as e:
        response_data = {
            'status': e.status,
            'error_message': e.message
        }
    except Exception as e:
        traceback.print_exc()
        print(e)
        response_data = {
            'status': 0,
            'error_message': err_msg
        }
    return Response(data=json.dumps(response_data), status=status.HTTP_200_OK)

Is this is a good design approach ? Is there any better/alternative way we can handle this ?

7
  • Why do you think this isn't robust, and what makes you believe efficiency is an issue here? – Philip Kendall Apr 19 at 13:02
  • Is this is a good design approach -- Does it effectively meet your specific software requirements? – Robert Harvey Apr 19 at 14:25
  • 1
    See also codereview.stackexchange.com, but read their Help Center first. – Robert Harvey Apr 19 at 14:26
  • @PhilipKendall Sorry, the question wasn't framed right. I am a beginner, so wanted to know if, what I am doing is right or is there any better way to handle this – Gowtham Bhat Apr 19 at 18:18
  • @RobertHarvey It meets my software requirements, but just wanted to know if this is standard or is there any better way I can handle this Nd – Gowtham Bhat Apr 19 at 18:21
1

In response to the above responses to my above post, I've decided that it's best to reply with "another answer." Here goes.

Instead of(!) regarding "an exception" as being "something bad happened, so we're all gonna die," expand your thinking to say that it represents: "any(!) 'exception to the rule.'"* That is: "any(!) ... well, "exception(!)" ... to the usual flow of processing."

Now, you can simply write your "add to cart" logic in the most-straightforward way: take the product-code, find the product, reserve a copy of it, and add it to the cart. Done. Simple logic, very straightforward, and almost(!) always what actually takes place! "The usual flow of processing, without exception."

Of course, as we all perfectly well know, "things can go wrong." The product-code is invalid, the product is not in stock, the cart doesn't like it. Instead of demanding that the main-line code handle all of these possibilities, we define alternative, parallel execution paths. Which we now refer to as: "exceptions."

When any piece of logic, anywhere, realizes that "something 'exceptional' has just happened," it is now able to enter into one of those parallel execution paths by "throwing an exception [object]." This "exception" might or might not(!) represent "a fatal error."

The parallel execution path now consists of "catchers," and each one of them has two choices: either they can absorb the exception (thereby killing it), or they can observe that it has taken place, maybe add something to it, and re-throw it to "the next catcher, if any."

The value of subdividing your exceptions into a hierarchy of subclasses – if there actually is such value in your particular application – is that it permits you to be more or less specific as to exactly what a particular "catcher" is actually interested in "catching."

If any exception "actually makes it all the way to the top," then the program dies – or, as the case may be, the web server hands out 500 Internal Server Error. But notice that there are now two distinct possibilities here: (1) that the situation actually was "we're all gonna die," or (2) it was a known-to-us(!) "exceptional situation" that should have been "caught" somewhere but wasn't.

--- 150% of all of the above is not in any way "specific to Python."

0

The only problem that I see: Your exceptions look like they contain messages to be shown to the user. Messages shown to the user should be created by your ui people and not come from a random exception.

2
  • They can be created by your "UI people" and still be part of an exception message. Not sure why you think these two things are mutually-exclusive. – Robert Harvey Apr 19 at 20:55
  • How do you suggest handling things ? Should I send a custom error code to front-end based on the type of the error? I am using the same structure to handle things like accessing DB, AWS, external APIs and print the error message if it fails in any of these steps. – Gowtham Bhat Apr 20 at 1:43
0

In principle, this is a solid and frequently-used strategy (in any language). However ...

I wouldn't just define one "custom exception," but an entire exception-class hierarchy. For instance, in your example you have "authentication errors," "product out of stock," and "cart errors." Broad categories of exceptions might be specialized by child classes as needs require.

In many complex systems, these exceptions might be of interest to several nested levels of exception trapping. Some might be reported to the user, while some might be absorbed internally. (For instance, code which seeks to "an an item to a cart" might be interested in several "exceptional" reasons why it cannot do so. These exceptions should never wound up being caught by the outermost-level handler and it would indicate an internal logic error if any ever did.

The "payload" of each exception may or may not itself include "a message." For instance, an "out of stock" exception might only contain a product-id and perhaps some reason code. Use your best judgment.

2
  • What benefit does an elaborate hierarchy of exception classes provide that isn't already adequately served by a generic "something bad happened that we cannot recover from internally" exception? You can't use exceptions for flow control, so... (well, you can, but why would you?) Web servers that throw often respond to the user with Internal Error 500 and no other information. – Robert Harvey Apr 19 at 20:56
  • Can you please provide me any example implementation of such exception handling? It would help a lot. – Gowtham Bhat Apr 20 at 1:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.