[Twisted-web] JSON "page" and nevow
Vincent Bernat
bernat at luffy.cx
Sat Aug 16 08:36:47 EDT 2008
Hi!
There are several pages that I would like to serve as JSON page. Nevow
include a JSON serializer but it seems there is no facility to send a
page as JSON.
Here is what I do:
,----
| class JsonPage(rend.Page):
|
| docFactory = loaders.stan ( T.div(render=T.directive("json"),
| data=T.directive("json")))
| addSlash = True
| flattenFactory = lambda self, *args: flat.flattenFactory(*args)
|
| def render_json(self, ctx, data):
| """Render the given data in a proper JSON string"""
|
| def sanitize(data, d=None):
| """Nevow JSON serializer is not able to handle some types.
|
| We convert those types in proper types:
| - string to unicode string
| - PgSQL result set into list
| - handling of deferreds
| """
| if type(data) in [list, tuple] or isinstance(data, PgSQL.PgResultSet):
| return [sanitize(x, d) for x in data]
| if type(data) == str:
| return unicode(data)
| if isinstance(data, rend.Fragment):
| io = StringIO()
| writer = io.write
| finisher = lambda result: io.getvalue()
| newctx = context.PageContext(parent=ctx, tag=data)
| data.rememberStuff(newctx)
| doc = data.docFactory.load()
| newctx = context.WovenContext(newctx, T.invisible[doc])
| fl = self.flattenFactory(doc, newctx, writer, finisher)
| fl.addCallback(sanitize, None)
| d.append(fl)
| return fl
| if isinstance(data, defer.Deferred):
| if data.called:
| return sanitize(data.result)
| return data
| if isinstance(data, failure.Failure):
| return unicode(
| "<span class='error'>An error occured (%s)</span>" % data.getErrorMessage())
| return data
|
| def serialize(data):
| return json.serialize(sanitize(data))
|
| d = []
| data = sanitize(data, d)
| d = defer.DeferredList(d)
| d.addCallback(lambda x: serialize(data))
| return d
|
|
| def beforeRender(self, ctx):
| inevow.IRequest(ctx).setHeader("Content-Type", "application/json; charset=UTF-8")
`----
I inherit of this class and just implement data_json. The main point is
that I should be able what I do for regular web pages, including the use
of deferred.
There are several drawbacks:
- I need to use deferred.called and deferred.result that is not part of
the public API. I don't know how to avoid this. JSON serializer does
not handle deferred (Fragments are rendered synchronously).
- to render Fragment, I use some obscur tricks that I stole from
rend.py. Not sure that this would survive.
- for Fragment, serializers will turn "<" into "<". Therefore, I
should turn them back as "<" on Javascript side. I did not found a
way to avoid serializing twice. It seems that T.xml instead of T.div
would do the trick but it does not support data and render
attributes.
- Nevow JSON serializer seems not te be extended to support more
types. Is it some plans to allow this?
Any tip to simplify or enhance the above code would be welcome.
Thanks.
--
Write and test a big program in small pieces.
- The Elements of Programming Style (Kernighan & Plauger)
More information about the Twisted-web
mailing list