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()