Add description to 404 and 409 error responses
It would be better if Zaqar could provide descriptions in it's 404 and 409 error response bodies. Reasons: 1. RFC 7231 asks to do it: https://tools.ietf.org/html/rfc7231#section-6.5 2. Sometimes it might be hard for the user to figure out why Zaqar returns 409 response code without description in response body. 3. Zaqar already provides descriptions in these error responses: 400 401 403 500 503 406 4. Keystone project is a good example of a project, which includes info in 404 responses. We can follow this example. This patch makes it so. Change-Id: I0d5c5b73498a40b5ec949ceb74f9bb7dcf925009 Closes-Bug: 1547258
This commit is contained in:
parent
830c54dc55
commit
d97327e95b
@ -65,3 +65,22 @@ class HTTPForbidden(falcon.HTTPForbidden):
|
||||
|
||||
def __init__(self):
|
||||
super(HTTPForbidden, self).__init__(self.TITLE, self.DESCRIPTION)
|
||||
|
||||
|
||||
class HTTPConflict(falcon.HTTPConflict):
|
||||
"""Wraps falcon.HTTPConflict with contextual title."""
|
||||
|
||||
TITLE = _(u'Resource conflict')
|
||||
|
||||
def __init__(self, description, **kwargs):
|
||||
super(HTTPConflict, self).__init__(self.TITLE, description, **kwargs)
|
||||
|
||||
|
||||
class HTTPNotFound(falcon.HTTPNotFound):
|
||||
"""Wraps falcon.HTTPConflict with contextual title."""
|
||||
|
||||
TITLE = _(u'Not found')
|
||||
|
||||
def __init__(self, description):
|
||||
super(HTTPNotFound, self).__init__(title=self.TITLE,
|
||||
description=description)
|
||||
|
@ -110,7 +110,7 @@ class ItemResource(Resource):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
description = _(u'Claim could not be queried.')
|
||||
@ -151,7 +151,7 @@ class ItemResource(Resource):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -98,7 +98,7 @@ class CollectionResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
@ -159,7 +159,7 @@ class CollectionResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except storage_errors.MessageConflict as ex:
|
||||
LOG.exception(ex)
|
||||
@ -247,7 +247,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -45,7 +45,7 @@ class Resource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
@ -78,8 +78,8 @@ class Resource(object):
|
||||
LOG.debug(ex)
|
||||
raise wsgi_errors.HTTPBadRequestAPI(six.text_type(ex))
|
||||
|
||||
except storage_errors.QueueDoesNotExist:
|
||||
raise falcon.HTTPNotFound()
|
||||
except storage_errors.QueueDoesNotExist as ex:
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -42,7 +42,6 @@ import six
|
||||
|
||||
from zaqar.common.api.schemas import pools as schema
|
||||
from zaqar.common import utils as common_utils
|
||||
from zaqar.i18n import _
|
||||
from zaqar.storage import errors
|
||||
from zaqar.storage import utils as storage_utils
|
||||
from zaqar.transport import utils as transport_utils
|
||||
@ -145,7 +144,7 @@ class Resource(object):
|
||||
|
||||
except errors.PoolDoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
data['href'] = request.path
|
||||
|
||||
@ -181,8 +180,7 @@ class Resource(object):
|
||||
response.location = request.path
|
||||
except errors.PoolAlreadyExists as e:
|
||||
LOG.exception(e)
|
||||
title = _(u'Unable to create pool')
|
||||
raise falcon.HTTPConflict(title, six.text_type(e))
|
||||
raise wsgi_errors.HTTPConflict(six.text_type(e))
|
||||
|
||||
def on_delete(self, request, response, project_id, pool):
|
||||
"""Deregisters a pool.
|
||||
@ -234,4 +232,4 @@ class Resource(object):
|
||||
self._ctrl.update(pool, **fields)
|
||||
except errors.PoolDoesNotExist as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
@ -13,8 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import falcon
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from zaqar.i18n import _
|
||||
from zaqar.storage import errors as storage_errors
|
||||
@ -56,7 +56,7 @@ class Resource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -137,7 +137,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
description = _(u'Claim could not be queried.')
|
||||
@ -178,7 +178,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -16,6 +16,7 @@
|
||||
import falcon
|
||||
import jsonschema
|
||||
from oslo_log import log
|
||||
import six
|
||||
|
||||
from zaqar.common.api.schemas import flavors as schema
|
||||
from zaqar.common import utils as common_utils
|
||||
@ -123,7 +124,7 @@ class Resource(object):
|
||||
|
||||
except errors.FlavorDoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
data['href'] = request.path
|
||||
|
||||
@ -204,4 +205,4 @@ class Resource(object):
|
||||
self._ctrl.update(flavor, project=project_id, **fields)
|
||||
except errors.FlavorDoesNotExist as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
@ -190,7 +190,7 @@ class CollectionResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except storage_errors.MessageConflict as ex:
|
||||
LOG.exception(ex)
|
||||
@ -226,7 +226,11 @@ class CollectionResource(object):
|
||||
# NOTE(TheSriram): Trying to get a message by id, should
|
||||
# return the message if its present, otherwise a 404 since
|
||||
# the message might have been deleted.
|
||||
resp.status = falcon.HTTP_404
|
||||
msg = _(u'No messages with IDs: {ids} found in the queue {queue} '
|
||||
u'for project {project}.')
|
||||
description = msg.format(queue=queue_name, project=project_id,
|
||||
ids=ids)
|
||||
raise wsgi_errors.HTTPNotFound(description)
|
||||
|
||||
else:
|
||||
resp.body = utils.to_json(response)
|
||||
@ -308,7 +312,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -148,7 +148,7 @@ class Resource(object):
|
||||
|
||||
except errors.PoolDoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
data['href'] = request.path
|
||||
|
||||
@ -188,8 +188,7 @@ class Resource(object):
|
||||
raise falcon.HTTPBadRequest(title, six.text_type(e))
|
||||
except errors.PoolAlreadyExists as e:
|
||||
LOG.exception(e)
|
||||
title = _(u'Unable to create pool')
|
||||
raise falcon.HTTPConflict(title, six.text_type(e))
|
||||
raise wsgi_errors.HTTPConflict(six.text_type(e))
|
||||
|
||||
def on_delete(self, request, response, project_id, pool):
|
||||
"""Deregisters a pool.
|
||||
@ -251,4 +250,4 @@ class Resource(object):
|
||||
self._ctrl.update(pool, **fields)
|
||||
except errors.PoolDoesNotExist as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
@ -46,7 +46,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -13,8 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import falcon
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from zaqar.i18n import _
|
||||
from zaqar.storage import errors as storage_errors
|
||||
@ -65,7 +65,7 @@ class Resource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -140,7 +140,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
description = _(u'Claim could not be queried.')
|
||||
@ -182,7 +182,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -16,6 +16,7 @@
|
||||
import falcon
|
||||
import jsonschema
|
||||
from oslo_log import log
|
||||
import six
|
||||
|
||||
from zaqar.common.api.schemas import flavors as schema
|
||||
from zaqar.common import utils as common_utils
|
||||
@ -137,7 +138,7 @@ class Resource(object):
|
||||
|
||||
except errors.FlavorDoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
data['href'] = request.path
|
||||
|
||||
@ -223,6 +224,6 @@ class Resource(object):
|
||||
for cap in capabilities]
|
||||
except errors.FlavorDoesNotExist as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
resp_data['href'] = request.path
|
||||
response.body = transport_utils.to_json(resp_data)
|
||||
|
@ -192,7 +192,7 @@ class CollectionResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except storage_errors.MessageConflict as ex:
|
||||
LOG.exception(ex)
|
||||
@ -229,7 +229,11 @@ class CollectionResource(object):
|
||||
# NOTE(TheSriram): Trying to get a message by id, should
|
||||
# return the message if its present, otherwise a 404 since
|
||||
# the message might have been deleted.
|
||||
resp.status = falcon.HTTP_404
|
||||
msg = _(u'No messages with IDs: {ids} found in the queue {queue} '
|
||||
u'for project {project}.')
|
||||
description = msg.format(queue=queue_name, project=project_id,
|
||||
ids=ids)
|
||||
raise wsgi_errors.HTTPNotFound(description)
|
||||
|
||||
else:
|
||||
resp.body = utils.to_json(response)
|
||||
@ -313,7 +317,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -151,7 +151,7 @@ class Resource(object):
|
||||
|
||||
except errors.PoolDoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
data['href'] = request.path
|
||||
|
||||
@ -192,8 +192,7 @@ class Resource(object):
|
||||
raise falcon.HTTPBadRequest(title, six.text_type(e))
|
||||
except errors.PoolAlreadyExists as e:
|
||||
LOG.exception(e)
|
||||
title = _(u'Unable to create pool')
|
||||
raise falcon.HTTPConflict(title, six.text_type(e))
|
||||
raise falcon.HTTPConflict(six.text_type(e))
|
||||
|
||||
@acl.enforce("pools:delete")
|
||||
def on_delete(self, request, response, project_id, pool):
|
||||
@ -258,7 +257,7 @@ class Resource(object):
|
||||
resp_data = self._ctrl.get(pool, False)
|
||||
except errors.PoolDoesNotExist as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
resp_data['href'] = request.path
|
||||
response.body = transport_utils.to_json(resp_data)
|
||||
|
@ -47,7 +47,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -13,8 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import falcon
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from zaqar.i18n import _
|
||||
from zaqar.storage import errors as storage_errors
|
||||
@ -65,7 +65,7 @@ class Resource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
@ -48,7 +48,7 @@ class ItemResource(object):
|
||||
|
||||
except storage_errors.DoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
@ -90,7 +90,7 @@ class ItemResource(object):
|
||||
resp.location = req.path
|
||||
except storage_errors.SubscriptionDoesNotExist as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPNotFound()
|
||||
raise wsgi_errors.HTTPNotFound(six.text_type(ex))
|
||||
except validation.ValidationFailed as ex:
|
||||
LOG.debug(ex)
|
||||
raise wsgi_errors.HTTPBadRequestAPI(six.text_type(ex))
|
||||
@ -187,8 +187,13 @@ class CollectionResource(object):
|
||||
description = _(u'Subscription could not be created.')
|
||||
raise wsgi_errors.HTTPServiceUnavailable(description)
|
||||
|
||||
resp.status = falcon.HTTP_201 if created else falcon.HTTP_409
|
||||
resp.location = req.path
|
||||
if created:
|
||||
resp.location = req.path
|
||||
resp.status = falcon.HTTP_201
|
||||
resp.body = utils.to_json(
|
||||
{'subscription_id': six.text_type(created)})
|
||||
else:
|
||||
description = _(u'Such subscription already exists. Subscriptions '
|
||||
u'are unique by project + queue + subscriber URI.')
|
||||
raise wsgi_errors.HTTPConflict(description, headers={'location':
|
||||
req.path})
|
||||
|
Loading…
Reference in New Issue
Block a user