def _get_method_name(self, has_iden): ''' Return resource object based on the HTTP method :param has_iden: specifies if requested url has iden (i.e /res/ vs /res/1) :type has_iden: bool :raises errors.MethodNotAllowedError: if HTTP method is not supprted :returns: name of the resource method name :rtype: str ''' method = self.request.method method = self.request.headers.get('HTTP_X_HTTP_METHOD_OVERRIDE', method) method_name = self.method_map.get(method.lower()) if not method_name: raise errors.MethodNotAllowedError( 'Method "{}" is not supported'.format(self.request.method)) if isinstance(method_name, tuple): method_name = method_name[has_iden] if not has_iden and self._iden_required(method_name): raise errors.BadRequestError('Given method requires iden') if has_iden and not self._iden_required(method_name): raise errors.BadRequestError('Given method shouldn\'t have iden') return method_name
def _get_payload(self, method_name): ''' Returns a validated and parsed payload data for request :param method_name: name of the method :type method_name: str :raises restea.errors.BadRequestError: unparseable data :raises restea.errors.BadRequestError: payload is not mappable :raises restea.errors.BadRequestError: validation of fields not passed :returns: validated data passed to resource :rtype: dict ''' if not self.request.data: return {} try: payload_data = self.formatter.unserialize(self.request.data) except formats.LoadError: raise errors.BadRequestError('Fail to load the data') if not isinstance(payload_data, collections.Mapping): raise errors.BadRequestError( 'Data should be key -> value structure') try: return self.fields.validate(method_name, payload_data) except fields.FieldSet.Error as e: raise errors.BadRequestError(str(e)) except fields.FieldSet.ConfigurationError as e: raise errors.ServerError(str(e))
def process(self, *args, **kwargs): ''' Processes the payload and maps HTTP method to resource object methods and calls the method :raises restea.errors.BadRequestError: wrong self.formatter type :raises restea.errors.ServerError: Some unhandled exception in resource method implementation or formatter serialization error :returns: serialized data to be returned to client :rtype: str ''' if not self._is_valid_formatter: raise errors.BadRequestError('Not recognizable format') method_name = self._get_method_name(has_iden=bool(args or kwargs)) self.payload = self._get_payload(method_name) method = self._get_method(method_name) method = self._apply_decorators(method) self.prepare() response = method(self, *args, **kwargs) response = self.finish(response) try: return self.formatter.serialize(response) except formats.LoadError: raise errors.ServerError('Service can\'t respond with this format')
def test_dispatch_exception(process_mock): resource, _, _ = create_resource_helper() resource.process.side_effect = errors.ServerError('Error!') res, status, content_type = resource.dispatch() assert res == json.dumps({'error': 'Error!'}) assert status == 503 assert content_type == 'application/json' resource.process.side_effect = errors.BadRequestError('Wrong!', code=101) res, status, content_type = resource.dispatch() assert res == json.dumps({'error': 'Wrong!', 'code': 101}) assert status == 400 assert content_type == 'application/json'
def _get_method(self, method_name): ''' Returns method based on a name :param method_name: name of the method :type method_name: str :raises errors.BadRequestError: method is not implemented for a given resource :returns: method of the REST resource object :rtype: function ''' method_exists = hasattr(self, method_name) if not method_exists: msg = 'Method "{}" is not implemented for a given endpoint' raise errors.BadRequestError(msg.format(self.request.method)) return getattr(type(self), method_name)
def test_dispatch_exception(process_mock): resource, _, _ = create_resource_helper() resource.process.side_effect = errors.ServerError('Error!') res, status, content_type, headers = resource.dispatch() assert res == json.dumps({'error': 'Error!'}) assert status == 503 assert content_type == 'application/json' assert headers == {} resource.process.side_effect = errors.BadRequestError('Wrong!', code=101) res, status, content_type, headers = resource.dispatch() expected_response = {'error': 'Wrong!', 'code': 101} assert set(json.loads(res).items()) == set(expected_response.items()) assert status == 400 assert content_type == 'application/json' assert headers == {} resource.process.side_effect = errors.ForbiddenError('Unauthorized!', login_path='/login') res, status, content_type, headers = resource.dispatch() expected_response = {'error': 'Unauthorized!', 'login_path': '/login'} assert set(json.loads(res).items()) == set(expected_response.items()) assert status == 403 assert content_type == 'application/json' assert headers == {} resource.process.side_effect = errors.NotFoundError( 'Not found!', code=101, redirect_path='/search') res, status, content_type, headers = resource.dispatch() expected_response = { 'error': 'Not found!', 'code': 101, 'redirect_path': '/search' } assert set(json.loads(res).items()) == set(expected_response.items()) assert status == 404 assert content_type == 'application/json' assert headers == {}