Search code examples
pythonspyne

JsonDocument as input protocol but method name taken from URL


From the example at spyne.io:

class HelloWorldService(ServiceBase):
    @srpc(Unicode, Integer, _returns=Iterable(Unicode))
    def say_hello(name, times):
        for i in range(times):
            yield 'Hello, %s' % name

application = Application([HelloWorldService],
    tns='spyne.examples.hello',
    in_protocol=JsonDocument(validator='soft'),
    out_protocol=JsonDocument()
)

This means that called method name must be the one and only key of JSON body:

$ curl -s http://localhost:8000/ -d '{"say_hello": {"name": "World", "times": 5}}'

I want the body to not include method name, but method name to be taken from URL, the same way it's done with HttpRpc:

$ curl -s http://localhost:8000/say_hello -d '{"name": "World", "times": 5}'

How do i define the service to be able to process such requests?


Solution

  • You could derive a new protocol type from JsonDocument. You only have to rewrite one method:

    # Tested with spyne.__version__=='2.10.9'
    class warwarukDocument(JsonDocument):
        """An implementation of the json protocol
           with the method name stored in the URL,
           not the document."""
    
        def create_in_document(self, ctx, in_string_encoding=None):
            """ Sets ``ctx.in_document`` using ``ctx.in_string``."""
            assert ctx.transport.type.endswith('http'), \
                   "This protocol requires an http transport, not %r (in %r)" \
                       % (ctx.transport.type, ctx.transport)
    
            super(warwarukDocument, self).create_in_document(ctx, in_string_encoding)
            # Not 100% sure where to find the URL path
            try:
                # Works for twisted
                uri = ctx.transport.req.uri
            except AttributeError:
                # Works for WSGI
                uri = ctx.transport.req['PATH_INFO']
            uri = re.sub(r'.*/', '', uri)
            ctx.in_document = { uri : ctx.in_document }
    
    
    application = Application([HelloWorldService],
        tns='spyne.examples.hello',
        in_protocol=warwarukDocument(validator='soft'),
        out_protocol=JsonDocument()
    )
    

    Usage:

    $ curl -s http://localhost:8000/say_hello \
          -d '{"name": "World", "times": 1}' | python -m json.tool
    [
        "Hello, World"
    ]
    $ curl -s http://localhost:8000/say_goodbye \
          -d '{"name": "World", "times": 1}' | python -m json.tool
    {
        "detail": null, 
        "faultcode": "Client.ResourceNotFound", 
        "faultstring": "Requested resource \"Method u'{spyne.examples.hello}say_goodbye' not found.\" not found"
    }