twisted / klein

werkzeug + twisted.web
Other
836 stars 121 forks source link

MIME, someday, maybe* #78

Open glyph opened 9 years ago

glyph commented 9 years ago

In a properly REST application, the server should engage in content negotiation to deliver the client's preferred representation of a resource.

I would love to make it possible, within klein, to separate the reification of the resource (i.e. instantiation of a model object) from the serialization of that resource (i.e. invocation of a view).

For example: let's say we have an API, /foo, which is a JSON API that returns {"foo": "bar"}. However, the user might hit it in a web browser, where it might be more helpful to present this information via an HTML template (rendered, perhaps, via twisted.web.template).

I'd love to do something like this:

@something("/foo")
def foo(request, values):
    return {"foo": "bar"}

@foo.serializer("text/html")
def as_html(request, model):
    return someTemplate.fillSlots(**model)

@foo.serializer("application/json")
def as_json(request, model):
   return json.dumps(model)

Of course, serializing as JSON and HTML are probably two pretty common ones, so maybe there should be a less verbose way to set this up, simply a way to specify a template. I am not sure how this should look, I'd just like it to be easy. Also, this should be possible on inputs as well: you might want to accept parameters as either JSON or urlencoded key/value pairs.

*: With apologies to Marc Andreessen.

wsanchez commented 7 years ago

I potentially disagree with the example provided:

A JSON document that describes some data and an HTML document that displays that data (in one of many possible ways) are not the same "concept" and should not be vended by the same resource, so the thing Glyph wants to do here is not, in fact, something a proper REST application should do.

That said, a JSON document that describes some data and a Protobuf or XML or whatever document that represents the same data may be an appropriate use of content negotiation, as would a photo that can be rendered as a JPG or PNG or whatever.

I mention that because if we end up with an example like this as a recommended way to write an app, I think that's unfortunate.

glyph commented 7 years ago

OK, I regret beginning with "properly REST" :). I don't put much stock in REST as a formal application architecture, and I don't really care if we are adhering to its religious tenets or not. It's very hard to tell if this specific idea (HTML including presentation information & JSON including only structure from the same resource) is "really" REST or not. There are some indications that it is, but there's more consensus that content negotiation generally is part of REST for deciding on different formats rather than different structures.

So, putting aside the idea of whether they're "really" the same concept or not: what's the benefit? As this blogger puts it, "less duplication of code".

If you're writing a web application that retrieves data from a backend, performs some logic, and returns it to a front-end, I believe it should be a strongly encouraged default that you should have structured data be available on day 1, even if what you're really targeting for reasons of optimization, SEO, or user experience is a prerendered HTML page. The goal here is not to commit to the same URL structure but rather to the same code. The negotiation is already rather ad-hoc (a query parameter, see #132), and there are good tooling reasons to avoid a pure Accept:-header based negotiation strategy. A URL segment might also be a perfectly reasonable way to accomplish the negotiation process, for example, exposing a /api/ prefix which is always JSON and an /app/ prefix which is always HTML.

So, all that said: what exactly do you think is the problem with offering these two resources from the same URL? What difficulties might it present? Would it be better to come up with some other default?