Rajani's weblog

 
Filed under

python

 

xkcd: Python.. :)

Media_httpimgsxkcdcom_gfsrf

Filed under  //   python   xkcd  

Comments [0]

wsloader : web-servicify python code without writing any HTTP/web-service specific code. http://code.google.com/p/wsloader/wiki/QuickStart#

 by tnhashmi
QuickStart  
Quick-start Guide for Webservice Loader

Python Webservice Loader

 

  • 2. wsloader Design and Architecture
  • 3. Installation Steps
  • 4. Service Configuration
  • 5. Future Improvements
  • 1. Introduction

    Python Webservice Loader (wsloader) is a WSGI application and protocol to allow exposing native Python interfaces as REST-like webservices without writing any HTTP/web-service specific code to expose a new service.

    It is developed by Lulu India for providing user data management services to weRead.

    1.1 Objectives

    The objectives of wsloader are:

    1. Minimal/Zero extra code and configuration to expose Python interfaces as a webservice
    2. Clean separation of webservice delivery mechanism and service implementation
    3. Full encapsulation of webservice protocols and mechanisms for authentication, authorisation, serialisation, end-point discovery and loading, logging and load balancing

    1.2 Features

    1.3 Why Not Django?

    The reasons to use wsloader instead of Django (or any other Python web framework) for exposing web-services are:

    1. Django is a Web Application framework, not a Web Service framework
    2. Django does a good job of mapping coarse-grained URLs to application logic but it does a poor job of simplifying fine-grained API invocation
    3. Django does a great job of creating dynamic, data rich web pages with styling and interaction elements which are not needed for APIs consumed by programs instead of humans
    4. Django requires programming in a specific style which makes it easier to do the heavy-lifting for web application development but is too complex for web service API delivery
    5. Django applications can not be deployed in non-Django environments. They are written specifically for Django

    wsloader itself is not a framework built from scratch, though. It is built upon Werkzeug micro-framework. Werkzeug was chosen based on a comparison by principles of over a dozen Python web application frameworks and web micro-frameworks, followed by an in-depth evaluation of 3 short-listed frameworks -- Django, Pylons and Wekzeug.

    2. wsloader Design and Architecture

    2.1 Implementation Format

    In its current form, wsloader is build as a WSGI application that integrates with apache2 using mod_wsgi. The application defines a module discovery protocol based on the URL structure.

    mod_wsgi restricts access to sys.stdin and sys.stdout. However, sys.stderr is mapped to Apache error log and is available to all modules that wish to be integrated.

    1. Web Server Gateway Interface, PEP 333
    2. mod_wsgi

    2.2 Application State Management

    wsloader loads a list of modules/classes to expose from a set of configuration files as services. The services are loaded on first use and remain loaded till the end of the apache process in which they were loaded.

    The Python interpreter is run in embedded mode like PHP and each new HTTP process starts with a fresh application state. The WSGI application is loaded once at server startup and can be configured to either be automatically reloaded when the application implementation changes or remain unchanged.

    Services that are implemented as classes get instantiated once on each request.

    2.3 URL Mapping

    wsloader creates a URL for service callables by replacing dots with slashes. E.g. datetime.datetime.now() can be invoked as a webservice using the URL

    http://example.com/datetime/datetime/now

    The last part of the URL's path must be a callable. The module/class configuration can be changed to provide alternate paths to the module/class but the name of the callable endpoint can not be changed.

    E.g. If you have a module foo.bar.baz.hello that exposes a function say_hello, you can potentially assign a prettier name to the module, say, greeter but say_hello remains unchanged. So the default URL,

    http://example.com/foo/bar/baz/hello/say_hello

    changes to

    http://example.com/greeter/say_hello

    2.4 HTTP Request Method Restriction

    wsloader enforces the 'POST' method for any callable endpoint that starts with one of the following (case-sensitive) prefixes:

       add, post, submit, set, update, delete

    For all other methods, only GET method is allowed.

    This allows service implementers to indicate read and write operations through intuitive function names without having them to bother about HTTP method enforcement or configuring it separately. It also allows the clients to use the appropriate HTTP method for making the call without requiring any configuration a priori. The HTTP middleware can then do the Right Thing™ with respect to request submissions, validation and cache control.

    2.5 Request Parameter and Response Handling

    All the parameter values and the response must be JSON encoded. For GET methods, the parameters should be passed in the query string. For POST methods, the parameters should be passed as the form data.

    2.5.1 Positional Parameters

    Positional parameters are passed to the end-point through a parameter called "args", which is a Form encoded JSON array of argument values.

    http://example.com/greeter/say_hello?args=["World"]

    calls

    greeter.say_hello("World")

    2.5.2 Named Parameters

    If the parameter "args" does not appear in the request data, the remaining non-protocol parameters are passed to the end-point as keyword arguments. E.g.

    http://example.com/greeter/say_hello?addressee="mes+amis"&greeting="Bon+jour"

    is equivalent to the following Python code:

    >>> greeter.say_hello(addressee="mes amis", greeting="Bon jour")

    3. Installation Steps

    1. Install werkzeug and libapache2-mod-wsgi
  • Check out wsloader-wsgi from the mercurial repository:
  • Install src/wsloader.py in /var/www/wsgi/ directory
  • Install config/wsloader.conf in apache's conf.d directory, wherever it lives on your system
  • Restart httpd.
  • Please note that the default config in wsloader.conf re-routes all URLs to wsloader. If you want to restrict this to a specific sub-path, examplepath, substitute:

    WSGIScriptAlias / /var/www/wsgi/wsloader.py

    with

    WSGIScriptAlias /examplepath /var/www/wsgi/wsloader.py

    Please consult apache2 and mod_wsgi documentation for more advanced configurations

    4. Service Configuration

    4.1 Default Configuration

    To expose a module with default URL construction, create an empty file with the module's import path as the file name in /etc/wsloader-wsgi

    E.g. to expose foo.bar.baz.hello module, do:

    $ sudo touch /etc/wsloader-wsgi/foo.bar.baz.hello

    4.2 Custom base URL for module/class

    If you want to remap the module/class to a different URL scheme, create the file with the pretty module path and add the alias_to= property in the file.

    E.g. to remap foo.bar.baz.hello to service.greeter, do:

    $ echo 'alias_to=foo.bar.baz.hello' > service.greeter$ sudo cp service.greeter /etc/wsloader-wsgi/

    Now the service can be called as

    http://example.com/service/greeter/<endpoint>

    instead of

    http://example.com/foo/bar/baz/hello/<endpoint>

    4.3 Exposing a class

    If you want to expose a class, instead of a module, put type=class in the corresponding file. By default it should be possible to instantiate the class without any construction parameters. However, you can use the init_param= property to specify loading the constructor argument from a named request parameter. E.g. in the following config:

    $ cat /etc/wsloader-wsgi/pgreetertype=classalias_to=foo.bar.baz.hello.pGreeterinit_param=greeting

    ... we are loading a class called pGreeter from the module foo.bar.baz.hello. The constructor argument for the class is to be taken from the request parameter greeting. So, you can call this endpoint as:

    http://example.com/pgreeter/say_hello?greeting="Hola"&args=["amigos"]

    This is equivalent to the following Python code:

    >>> foo.bar.baz.hello.pGreeter("Hola").say_hello("amigos")

    5. Future Improvements

    That is it with wsloader as of now. In the near future wsloader is targetting the following enhancements:

    If you can think of a feature that wsloader can support while being able to meet its objectives, please do log it in the issue tracker.

    Happy hacking!

     

    Filed under  //   python   web-services   wsloader  

    Comments [0]