Exceptions

Structure

In blargh exceptions are used internally to end processing of each request that has to fail. In looks more or less like this:

class Internals:
    def process_data(data):
        if Internals.invalid_data(data):
            raise SomeException(msg="invalid data")
        return 200, {'result': 'success'}

class Api:
    def make_request(data):
        try:
            processed_data = Internals.process_data(data)
            return 200, processed_data
        except SomeException as e:
            return e.status, e.details

#   and our final user call is processed
Api.make_request({'some': data})

Contents of blargh.exceptions:

Error
  ProgrammingError
  ServerError
    e500
    TransactionConflictRetriable
  ClientError
    e400
      FieldDoesNotExists
      FieldIsReadonly
      FieldUpdateForbidden
      SearchForbidden
      BadParamValue
      BadFieldValue
    e401
    e404
    e422

Briefly speaking:

  • ProgrammingError indicates that probably blargh user did something wrong
  • ClientError indicates that application user did something wrong, and its descendants are related to specific kinds of mistakes
  • e500 is raised when we encounter unexpected internal errors, e.g. disconnected database
  • TransactionConflictRetriable is raised when request fails, but can be repeated (and Api.make_request is called again). Its only raised by PGStorage and more detailed description is there.

Some of those exceptions are never raised by blargh, but could be raised by applications extening it.

List of error codes

Status Code Reason
400 bad_request Unknown client error. This could also be a generic database exception, with details containing more information (e.g. ‘ERROR: null value in column “id” violates not-null constraint’)
400 field_does_not_exists User request references non-existent object field.
400 field_is_readonly User tries to change a field he is not allowed to modify in a direct way.
400 field_update_forbidden User tries to change a field he is not allowed to modify in any way.
400 search_forbidden User attempted to filter results (probably GET) by a field that shouldn’t be used for filtering, e.g. by a Calc field or my multi retaltional field.
400 bad_param_value User sent invalid value of some url parameter, e.g. negative depth, or invalid json for filter.
400 bad_field_value User tries to set field to an invalid value, e.g. to set ‘one’ to Scalar field with type_=int
401 unauthorized Missing authorization header
404 object_does_not_exist Referenced object does not exists. This code for e.g. call PATCH cookie/1 {'jar': 7} might be returned both when cookie with id=1 is missing, or for missing jar with id=7.
422 unprocessable_entity (this currently never happens)
500 unknown_error We have no idea what failed. Probably an unexpected programming error.
500 server_error Something failed internally, e.g. could not connect to the database.

Exception interface

from blargh.exceptions import Error
try:
    raise Error(msg='something failed', what='no idea', where='also no idea')
except Error as e:
    print(e.status)    # 500
    print(e.code)      # 'unknown_error'
    print(e.details)   # {'msg': 'something failed',
                       #  'what': 'no idea',
                       #  'where': 'also no idea'}

    #   this is by default returned as response body when request fails
    print(e.ext_data)  # {'error': {'code': 'unknown_error',
                       #            'details': {'msg': 'something failed',
                       #                        'what': 'no idea',
                       #                        'where': 'also no idea'}