Skip to content

Exceptions

Cubed has custom Exceptions that we can raise, allowing us to deal with errors/validation however we'd like. This is especially useful for dealing with frontend errors and also backend commands.

Base Exception

backend/base/exceptions.py

Base Class to hold CubedError which extends from Exception, and CubedValidationError which extends from CubedError and allows an array of validation error messages.

class CubedError(Exception):    
    pass

class CubedValidationError(CubedError):
    validation_errors = []

    def __init__(self, errors):
        if type(errors) == str:
            errors = [errors]                        
        self.validation_errors += errors

Example

Cubed Exception Error

try:
    # code
except Exception:
    raise CubedError("Specific cubed error to manage")

Cubed Validation Error

try:
    # code
except Exception:
    raise CubedValidationError(["Field X is wrong type", "Field Y can not be null"])

Client Exceptions

backend/client/exceptions.py

Custom cubed exception classes to use as part of the Django ORM process.

Example

from base.exceptions import CubedError, CubedValidationError


class CubedPatternValidationError(CubedValidationError):
    pass

Client Validators

backend/client/models/validators.py

Apply custom validator functions for Django models raising the custom Exceptions.

Example

import re
from client.exceptions import CubedPatternValidationError

def validate_pattern(my_pattern, test=None):

    def compile_pattern(original):
        #code

    try:
        compiled_pattern = compile_pattern(my_pattern)           
        pat = re.compile(compiled_pattern, re.IGNORECASE)
    except Exception as ex:
        raise CubedPatternValidationError('Pattern is not valid')

This can then be handled differently in either backend or frontend.

Tastypie/API Exceptions

backend/api/exceptions.py

Custom CubedValidationException to force Tastypie to "exit" current request cycle and return a Validation error + msg for frontend to interpret. This avoids Django's handling of Exceptions in Production and the client receiving a correctly ambiguous 500 error - with no information.

Example

from tastypie.exceptions import ImmediateHttpResponse
from django.http import JsonResponse
from http import HTTPStatus

class CubedDuplicateException(ImmediateHttpResponse):
    # https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409
    def __init__(self, msg):
        self._response = JsonResponse({
                  'code': 409,
                  'message': msg
                }, status=HTTPStatus.CONFLICT)

Tastypie/API Validators

backend/api/validators.py

Custom functions to apply validation to Tastypie resources.

Example

Here is an example of using a combination of the previously discussed classes and functions. Here we inherit the Tastypie base Validation class, and override the is_valid function to call our own custom validation function.

from tastypie.validation import Validation
from client.models.validators import validate_pattern
from client.exceptions import CubedPatternValidationError

class PatternValidation(Validation):

    def check_pattern(self, errors, test_pattern):
        try:
            errors = validate_pattern(test_pattern)
        except CubedPatternValidationError as ex:            
            errors['pattern'] = ex.validation_errors
        return errors

    def is_valid(self, bundle, request=None):        
        errors = {}
        test_pattern = bundle.data['pattern']        
        self.check_pattern(errors, test_pattern)

        return errors

Class used in Tastypie Resource:

from api.resources.validators import PatternValidation

class PatternResource(ModelResource):
    referer = fields.ForeignKey(RefererResource, 'referer', readonly=False)

    class Meta(CommonMeta):
        queryset = Pattern.objects.filter(active=True)
        resource_name = 'pattern'
        ordering = ['created', '-created']
        filtering = {'pattern': ALL_WITH_RELATIONS, 'referer': ALL_WITH_RELATIONS, 'active' : True}
        limit = 0
        always_return_data = True

        validation = PatternValidation()