Python Client Stub Generator

The RESTCoder’s Python client stub generator can be used to quickly and easily generate Python modules that can consume remote web APIs. The generated code handles data marshaling, unmarshaling, HTTP invocation and also in many cases error handling, thereby relieving the mashup and application developers from having to manually implement all that logic. If the input API description is properly documented, the Python code generated by the stub generator would have proper docstrings describing each of the auto-generated methods. By auto-generating code that masks all the complexities of communicating with a remote API, this tool greatly simplifies the process of developing mashups, desktop applications, command-line tools and webapps that rely on remote web services.

The following sections describe how to use the code generator and what to expect as its output.

Using the Python Code Generator

The Python client stub generator requires Python 2.7 to be installed. If Python 2.7 is already installed, simply head over to the bin directory of the RESTCoder installation and execute the script named codegen.py as follows.

./codegen.py -f /path/to/api/description.json -o mymodule.py

This will generate a Python module named mymodule.py which can be used as a client stub (proxy) to consume the remote API described in description.json.

It is also possible to load the input API description from a HTTP/S URL.

./codegen.py -u http://example.com/description.json -o mymodule.py

By default the HTTP OPTIONS method will be used to pull the API description from the input URL. To use a different method use the -m flag.

To see the full list of command line options supported by the Python code generator, run codegen.py with the -h flag.

./codegen.py -h

Generated Code

Python code generated by the client stub generator can be executed on any Python 2.7 runtime. The generated code is also highly backwards compatible with Python 2.6. The auto-generated code relies on following built-in Python modules.

The generated code may also rely on the api.py module shipped with the RESTCoder distribution. This module can be found in the python-lib directory of RESTCoder.

The Python code generator, generates a separate Python class for each resource defined in the API description. The class is usually has the same name as the resource with the suffix Client appended to it. Operations of a resource are converted into methods of the corresponding generated class. Therefore if a particular input API description has a resource named OrderManager which has the operations getOrder and submitOrder, the code generator would generate a Python class named OrderManagerClient which has the functions getOrder() and submitOrder(). The input parameters of the two operations would be turned into Python method arguments and the output of the operations would be turned into return types.

The code generator would also generate separate classes for each of the data types defined in the input API description. Instances of these classes will be used as input arguments and return objects where appropriate. A separate set of static methods would be generated which handles serialization and deserialization of Python objects.

Media Types

As of now the Python code generator can only generate code for JSON based APIs (i.e. APIs that consume and produce JSON). If the input API description uses other media types, the code generator would create some place holder serialization/deserialization functions which simply raises the NotImplementedError exception.

def deserialize_VideoFeed_atomxml(obj):
  raise NotImplementedError

It is trivial to add support for other media types in the code generator tool. Simply implement a serializer extending the AbstractSerializer class of the serializers.py module. In this class, specify how to recursively convert a Python object into a byte string in the target media type and how to covert a byte string into a Python object. Refer the default JSONSerializer class in the same module for an example.

In situations where the target API supports multiple media types, you can force the code generator to stick to a single preferred media type when generating code by specifying the -d option.

./codegen.py -f /path/to/api/description.json -o mymodule.py -d json

Using the Generated Code

Simply import the generated module and use the client classes in the module to communicate with the remote API resources. The docstrings of the class methods would list all the input arguments accepted by each method.

def deleteVideo(self, videoId):
  """
  Args:
    videoId string

  Returns:
    An instance of the VideoFeedEntry class
  """
  query = ''
  conn = self.get_connection()
  ...

The generated methods will take care of marshaling input arguments, HTTP connection establishment and teardown and also unmarshaling response data. An example code snippet that uses a generated module is given below.

import youtube

if __name__ == '__main__':
  client = VideoSearchFeedClient()
  entries = client.getVideoFeed('api', alt='json', q='Google Glass').feed.entry
  print 'Found ' + str(len(entries)) + ' videos...'
  for item in entries:
    print item.title.t, '(Uploaded by:', item.author[0].name.t, ') - ', item.link[0].href

Error Handling

If the generated code encounters an error while invoking the target API, it would throw a RemoteException, which is a custom exception type defined in the generated module.

Using a Custom URL

By default, the generated code would communicate with the target API by making a HTTP connection to the base URL specified in the API description. But in some cases it would be required to communicate with the API using a custom URL (some gateway or proxy URL). To specify a custom URL, specify the endpoint argument in the constructor of the corresponding resource client.

import youtube

if __name__ == '__main__':
   client = VideoSearchFeedClient(endpoint='http://my.custom.url')
   ...

Debug Mode

The auto-generated code supports a special debug mode. When executed in this mode, the client code prints all the requests and responses exchanged with the backend API. To enable the debug mode, simply pass True to the debug argument of the constructor of the corresponding resource client.

import youtube

if __name__ == '__main__':
   client = VideoSearchFeedClient(debug=True)
   ...