Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should be able to specify serializer/deserializer on RestAPI.register #131

Open
turicas opened this issue Apr 7, 2014 · 5 comments
Open

Comments

@turicas
Copy link

turicas commented Apr 7, 2014

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 dict representing the object (flask_peewee.rest.RestResource will then create the object from the dict and do what is needed with it -- obj.save etc.).

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: list of dicts -- each dict represent one object data.

Note: by str I mean: str on Python 2 or bytes on 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.

@turicas
Copy link
Author

turicas commented Apr 7, 2014

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"
}

@turicas
Copy link
Author

turicas commented Apr 7, 2014

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).

@turicas
Copy link
Author

turicas commented Apr 7, 2014

SerializerDeserializer.serialize_object and SerializerDeserializer.serialize_collection should also accept optional parameters fields and exclude, as flask_peewee.serializer.Serializer.serialize_object currently supports.

@coleifer
Copy link
Owner

coleifer commented Apr 7, 2014

Good idea, I think offering the ability to register serializers/deserializers would go a long way.

@turicas
Copy link
Author

turicas commented Apr 7, 2014

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants