Should be able to specify serializer/deserializer on RestAPI.register
A good RESTful API can receive and answer requests in many formats (content types) and it would be nice if flask-peewee have this flexibility. With this implemented we can easily extend the API to support other formats (example: outputting JSON-LD instead of plain JSON, or XML, or even CSV etc.). I made a little specification of this new feature below for discussion:
Flexible Content-Types
Introduction
flask_peewee.rest.RestAPI.register method should support a formats parameter: a dictionary where keys are accepted content-types and values are serializer/deserializer objects that can handle it.
The code would be something like this:
json_serdes = ... # an object that can handle JSON serialization/deserialzation
xml_serdes = ... # the same, but for XML
supported_formats = {'application/json': json_serdes,
'application/xml': xml_serdes,}
api.register(MyModel, RestResource, formats=supported_formats)
flask_peewee.rest.RestAPI.__init__ should also accept a formats parameter that will default to all registered models in that object.
A parameter default_format should also be accepted by these two methods, representing the default serializer/deserializer to use if user send Accept: */* (for GET) or no Content-Type (for POST/PUT/DELETE). Note that 415 Unsupported Media Type should be answered if the specified content type is not available.
Serializer/Deserializer
The values of formats dict (json_serdes and xml_serdes in the example) should provide the following methods:
serialize_object
Method used serialize, for example, the result of a GET /api/<model>/<pk>/ (one object).
- Input parameters: a model instance and model class;
- Output:
str* object representing the object serialized (with possibliy some extra metadata) that will be returned to the HTTP client.
serialize_collection
Method used to serialize, for example, the result of a GET /api/<model>/ (many objects and possibly metadata such as pagination information).
- Input parameters: a query object and model class;
- Ouput: a
str* representing the objects serialized with metadata information (like pagination) that will be returned to the HTTP client.
deserialize_object
Method used to deserialize, for example, data coming from a POST /api/<model>/ (one object).
- Input parameters:
str* object representing the object serialized and model class; - Output: a
dictrepresenting the object (flask_peewee.rest.RestResourcewill then create the object from thedictand do what is needed with it --obj.saveetc.).
deserialize_collection
Method used to deserialize, for example, data coming from a POST /api/<model>/?bulk=true (many objects).
- Input parameters:
str* object representing objects serialized and model class; - Output:
listofdicts -- eachdictrepresent one object data.
Note: by
strI mean:stron Python 2 orbyteson Python 3.
Supporting JSON
By now, the default value for formats would be a dict with only the key application/json set (pointing to an object that have inside flask_peewee.serializer.Serializer and flask_peewee.serializer.Deserializer), like this:
from flask_peewee.serializer import Deserializer, Serializer
default_formats = {'application/json': (Serializer(), Deserializer())}
# TODO: implement `deserialize_collection` and `serialize_collection` for classes above
The default value of default_format should be application/json.
The serializer/deserializer objects may need more information, like some stored inside RestAPI object. It will be needed, for example, when you serialize an object but inside this serialization you need information about the URL for another resource/object.
Example: let's say we have a model Message with attributes user_from and user_to (foreign keys of User) and we want to link the user resources inside Message serialization so the output can be something like this (if it's s JSON serializer):
{
"message": "the answer is 42",
"postedOn": "2014-04-05T23:22:48Z",
"sender": "/api/user/1",
"receiver": "/api/user/2"
}
A little change: if the method run is RestResource.edit, and object instance (instead of model class) should be passed to SerializerDeserializer.deserialize_object (the same is valid for SerializerDeserializer.deserialize_collection).
SerializerDeserializer.serialize_object and SerializerDeserializer.serialize_collection should also accept optional parameters fields and exclude, as flask_peewee.serializer.Serializer.serialize_object currently supports.
Good idea, I think offering the ability to register serializers/deserializers would go a long way.
I've started the branch feature/flexible-content-types on my fork to work on this specification - it will need a big rewrite in many things! Can you please change the assignee of this issue for my username, please?