bottlepy / bottle

bottle.py is a fast and simple micro-framework for python web-applications.
http://bottlepy.org/
MIT License
8.37k stars 1.46k forks source link

@route content negotiation #1173

Open sharpaper opened 4 years ago

sharpaper commented 4 years ago

Does Bottle support content negotiation? Sometimes it's the client that specifies to the server what format it wants back, for example the same URL can be used to return an HTML version of the resource, or JSON, or RDF, or XML. Can Bottle support this? More or less like this:

@route('/resource', accept-header='text/html'):
def html():
    return resource as html

@route('/resource', accept-header='text/turtle'):
def turtle():
    return resource as turtle file

@route('/resource', accept-header='application/xml'):
def xml():
    return resource as xml file
defnull commented 4 years ago

No. Content negotiation is quite complex (if you actually want to implement the spec) and also a completely optional part of HTTP. Perhaps caused by the complexity and unintuitive rules, it is not used very widely. Most REST APIs or traditional webpages only offer a single representation per route and completely ignore the Accept header. Some even side-step the spec and allow users to add common file name extensions to request routes to choose an output format.

If you really need that, I'd suggest implementing it as a plugin or simple helper function hat calls different serializers and/or handler functions based on the best match. For example:

@route('/resource'):
def handle():
    data = ...

    return choose({
        'text/html; q=0.1': lambda: to_html(data),
        'text/turtle': lambda: to_turtle(data),
        'application/xml': lambda: to_xml(data),
    }, request.headers.get("Accept","*/*"))
sharpaper commented 4 years ago

I've just noticed that pyramid has something like this. See here, scroll down to "Predicate Arguments > header". Basically, before a request is dispatched to a controller it's possible to check if a header exist in addition to the method and pattern of the request. Would this be possible to do for Bottle as well? It wouldn't seem too difficult to check for a header, but I don't know...