REST applications should be able to respond to clients in more than one format. Sound a theory but practically REST applications speak one major format and make exceptions to the rule, e.g an exportable report for download in CSV, and delivering the same data to a client in JSON for visualization. Serializers may also require the REST application to format their data in very different ways, e.g JSON would be a tree style response where as CSV would be linear.
Many frameworks expect the REST handler to choose how each response should be serialized (based on URL patters), we end up creating more work (not to mention large if else blocks) for the typical scenarios to accomodate the exceptions. pretans takes a slightly different appraoch to this problem and pairs serializers
RESTApplication implementations. prestans REST handlers return either a prestans or Python type as their response and rely on the serializer to do their work, this enables you to reuse handlers with multiple serializers simply by referring to the same REST handler class from multiple end points.
The gotcha is mixing and matching serializers to REST handlers that follow similar structures. E.g Tree structures opposed to linear structures.
To make exceptions to the rule it’s recommended you create a separate URL scheme that fits the serialization format, mapped to appropriate and often exclusive REST handlers. Not all your business logic work should be done in your REST handlers, if they are reusable consider pushing the code into a common class or if you are using ORM layers consider distributing it based on the persistent models you are working with.
Serializers follow the prestans Provider (see Getting Started) paragradim. A serializer provides a wrapper on a pair of functions to write and read a data exchange format. It’s recommended you use standard Python functions to perform the serialize and unserialize operations for performance. However if you need to you can write a pure Python implementation of your serializer.
Serializers are never used directly, it’s always paired with a RESTApplication. We current provide support for the following serialization formats:
- JSON via
prestans.serializers.JSONSerializer, paired with
- YAML via
prestans.serializers.YAMLSerializer, paired with
3.1. Writing your own serializer¶
The Provider paradigm provides a really simple way for you to write your own serializers and pair them with custom
RESTApplication. This section discusses and demonstrates how simple it is to write your own serializers.
Serializers extend from
prestans.serializers.Serializer and expect you to implement these three methods (our example discusses the JSON serializer we ship with prestans):
loadsis responsible for unserializing input data for your application, it’s provided a Python
stringand is expected to return an python data type, usually an iterable.
dumpsprovided a pure Python object that may be itterable and needs to be serialized. This function must return the serialized data back to the caller. prestans is responsible for writing the data back to the client
get_content_typeis expected to send back the mime type of the serialization format in use as a python
prestans.serializers.UnserializationFailedException and gracefully handles the client response, if the serialization process has problems it’s recommended you raise this exception, with a meaningful message.
## @brief Provider for JSON based serializer # class JSONSerializer(Serializer): ## @brief loads method for JSON serializer # # @param self The object pointer # @param input_string # @classmethod def loads(self, input_string): import json parsed_json = None try: parsed_json = json.loads(input_string) except Exception, exp: raise UnserializationFailedException('Input Body data is not valid JSON') return parsed_json ## @brief dumps method for JSON serializer # # @param self The object pointer # @param serializable_object # @classmethod def dumps(self, serializable_object): import json return json.dumps(serializable_object) @classmethod def get_content_type(self): return 'application/json'
You can instantiate this class and test it works on the Python interactive interface. Once you are confident that your serializer wrapper works, proceed to pairing it with a RESTApplication that you create.
3.2. Pairing it with your REST Application¶
Nearly all of the
RESTApplication logic and the prestans API lifecycle is encapsulate in
prestans.rest.RESTApplication (this class is not paired with a serializer and never meant to be used directly). All custom implementations extend from
prestans.rest.RESTApplication and expect them to construct a
Response to be used by the API lifecycle. These objects expect the serializer
class they are meant to use.
REST Application implementations are required to override the following class methods:
make_requestexpected to return an instance of
prestans.rest.Request, and is passed in a reference to the WSGI environ
make_responseexpected to return an instance of
The following example is of the commonly used
JSONRESTApplication taken from the
## @brief REST Application Gateway that speaks JSON # class JSONRESTApplication(RESTApplication): @classmethod def make_request(self, environ): rest_request = Request(environ, serializer=prestans.serializers.JSONSerializer) return rest_request @classmethod def make_response(self): rest_response = Response(serializer=prestans.serializers.JSONSerializer) return rest_response
While it’s possible, it’s considered to be against the prestans design principles to pair a serializer with multiple RESTApplication implementations.