Files
deb-python-falcon/falcon/media/handlers.py
John Vrbanac 3495344ff4 feat: Request and Response media-type handling (#1050)
This is a first pass at a non-breaking change that'll allow for a customizable media handling system. This approach combines many of the suggestions brought up by the community in #145.

One the thing that is left out of this PR is handling full content negotiation (i.e. connecting the request's accept header to the response's content-type). Unfortunately, this is a harder problem to solve in a backwards compatible fashion that doesn't affect performance. However, especially as we move towards v2, I think that would be a great opportunity to revisit full negotiation. In the meantime, there are several easy workarounds for people needing this functionality.

Closes #145
2017-06-14 23:38:47 -06:00

55 lines
1.6 KiB
Python

import mimeparse
from six.moves import UserDict
from falcon import errors
from falcon.media import JSONHandler
class Handlers(UserDict):
"""A dictionary like object that manages internet media type handlers."""
def __init__(self, initial=None):
handlers = initial or {
'application/json': JSONHandler(),
'application/json; charset=UTF-8': JSONHandler(),
}
# NOTE(jmvrbanac): Directly calling UserDict as it's not inheritable.
# Also, this results in self.update(...) being called.
UserDict.__init__(self, handlers)
def _resolve_media_type(self, media_type, all_media_types):
resolved = None
try:
# NOTE(jmvrbanac): Mimeparse will return an empty string if it can
# parse the media type, but cannot find a suitable type.
resolved = mimeparse.best_match(
all_media_types,
media_type
)
except ValueError:
pass
return resolved
def find_by_media_type(self, media_type, default):
# PERF(jmvrbanac): Check via a quick methods first for performance
if media_type == '*/*' or not media_type:
return self.data[default]
try:
return self.data[media_type]
except KeyError:
pass
# PERF(jmvrbanac): Fallback to the slower method
resolved = self._resolve_media_type(media_type, self.data.keys())
if not resolved:
raise errors.HTTPUnsupportedMediaType(
'{0} is an unsupported media type.'.format(media_type)
)
return self.data[resolved]