Adapting a browser request into a web service request

Most of the time, web service requests come through the web service layer. But there are times when a request that came through the website neeeds to be treated as a web service request. It’s easy to adapt an IBrowserRequest into an IIWebServiceClientRequest request.

This adapters uses the request factory from the IWebServiceConfiguration utility.

>>> from lazr.restful.interfaces import (
...     IWebServiceConfiguration, IWebServiceClientRequest)
>>> from lazr.restful.publisher import (
...     browser_request_to_web_service_request)
>>> from lazr.restful.testing.webservice import WebServiceTestPublication
>>> from lazr.restful.simple import Request
>>> from zope.interface import implementer
>>> from zope.component import getSiteManager
>>> from zope.publisher.browser import TestRequest
>>> @implementer(IWebServiceConfiguration)
... class SimpleWebServiceConfiguration:
...     path_override = 'api'
...     active_versions = ['beta']
...
...     def createRequest(self, body_stream, environ):
...         request = Request(body_stream, environ)
...         request.setPublication(WebServiceTestPublication(None))
...         return request
>>> from lazr.restful.interfaces import IWebServiceVersion
>>> class IBetaVersion(IWebServiceVersion):
...     """Marker interface for web service version."""
>>> sm = getSiteManager()
>>> sm.registerUtility(SimpleWebServiceConfiguration())
>>> sm.registerUtility(IBetaVersion, IWebServiceVersion, name="beta")
>>> sm.registerAdapter(browser_request_to_web_service_request)
>>> website_request = TestRequest(SERVER_URL="http://cookbooks.dev/")
>>> request = IWebServiceClientRequest(website_request)
>>> request
<...Request...>
>>> request.getApplicationURL()
'http://cookbooks.dev/api/beta'

The JSON Cache

Objects can be stored in a cache so that they can be included in Javascript code inside the template. This is provided by the IJSONRequestCache. There is a default adapter available that works with any IApplicationRequest.

An object can be stored in the cache’s ‘objects’ dict or its ‘links’ dict.

>>> from lazr.restful.interfaces import IJSONRequestCache
>>> from lazr.restful.jsoncache import JSONRequestCache
>>> sm.registerAdapter(JSONRequestCache)
>>> cache = IJSONRequestCache(website_request)

The ‘objects’ dict is for objects that should have their full JSON representations put into the template.

>>> cache.objects['object1'] = 'foo'
>>> cache.objects['object2'] = 'bar'
>>> for key in sorted(cache.objects):
...     print("%s: %s" % (key, cache.objects[key]))
object1: foo
object2: bar

The ‘links’ dict is for objects that should have their self_links put into the template, not their whole representations.

>>> cache.links['objectA'] = 'foo'
>>> cache.links['objectB'] = 'bar'
>>> for key in sorted(cache.links):
...     print("%s: %s" % (key, cache.links[key]))
objectA: foo
objectB: bar

There is a TALES formatter available that can be used to obtain a reference to this cache from TALES:

>>> from lazr.restful.tales import WebServiceRequestAPI
>>> from lazr.restful.testing.tales import test_tales
>>> from zope.interface import Interface
>>> from zope.traversing.adapters import DefaultTraversable
>>> sm.registerAdapter(DefaultTraversable, [Interface])
>>> sm.registerAdapter(WebServiceRequestAPI, name="webservicerequest")
>>> cache = test_tales(
...     "request/webservicerequest:cache", request=website_request)
>>> for key in sorted(cache.links):
...     print("%s: %s" % (key, cache.links[key]))
objectA: foo
objectB: bar