title: Serializing SQLAlchemy models for a REST API while respecting access control?
body: <p>Currently, the way our, as well as most web frameworks', serialization works is there's some type of method invocation which dumps the model into some type of format. In our case, we have a <code>to_dict()</code> method on every model that constructs and returns a key-value dictionary with the key being the field name and the value being the instance variable.</p>
  
  <p>All throughout our code, we have snippets like the following: <code>json.dumps(**some_model_object.to_dict())</code> which will serialize a <code>some_model_object</code> to json. Recently, we've decided to expose some internal resources to our users, but some of these resources have specific private instance values that we do not want to transmit back during serialization if the requesting user is not a super user.</p>
  
  <p>I'm trying to come up with a clean design that will allow easier serialization, as well as allow us to serialize to a format other than json. I think this is a pretty good use case for Aspect Oriented Design/Programming, where the aspects respect the requesting access controls and serialize the object based on the requesting user's persmissions.</p>
  
  <p>Here's something similar to what I have now:</p>
  
  <pre><code>from framework import current_request
  
  
  class User(SQLAlchemyDeclarativeModel):
      __tablename__ = 'users'
  
      id = Column(Integer, primary_key=True)
      first_name = Column(Unicode(255))
      last_name = Column(Unicode(255))
      private_token = Column(Unicode(4096))
  
      def to_dict(self):
          serialized = dict((column_name, getattr(self, column_name))
                            for column_name in self.__table__.c.keys())
  
          # current request might not be bound yet, could be in a unit test etc.
          if current_request and not current_request.user.is_superuser():
              # we explicitly define the allowed items because if we accidentally add
              # a private variable to the User table, then it might be exposed.
              allowed = ['id', 'first_name', 'last_name']
              serialized = dict((k, v) for k, v in serialized.iteritems() if k in allowed)
  
          return serialized
  </code></pre>
  
  <p>As one can see, this is less than ideal because now I have to couple the database model with the current request. While this is <em>very</em> explicit, the request coupling is a code smell and I'm trying to see how to do this cleanly.</p>
  
  <p>One way I've thought about doing it is to register some fields on the model like so:</p>
  
  <pre><code>class User(SQLAlchemyDeclarativeModel):
      __tablename__ = 'users'
      __public__ = ['id', 'first_name', 'last_name']
      __internal__ = User.__exposed__ + ['private_token']
  
      id = Column(Integer, primary_key=True)
      first_name = Column(Unicode(255))
      last_name = Column(Unicode(255))
      private_token = Column(Unicode(4096))
  </code></pre>
  
  <p>Then, I would have a serializer class that is bound with the current request on every WSGI call that will take the desired serializer. For example:</p>
  
  <pre><code>import simplejson
  
  from framework import JSONSerializer  # json serialization strategy
  from framework import serializer
  
  # assume response format was requested as json
  serializer.register_serializer(JSONSerializer(simplejson.dumps))
  serializer.bind(current_request)
  </code></pre>
  
  <p>Then in my view somewhere, I would just do:</p>
  
  <pre><code>from framework import Response
  
  user = session.query(User).first()
  return Response(code=200, serializer.serialize(user))
  </code></pre>
  
  <p><code>serialize</code> would be implemented as follows:</p>
  
  <pre><code>def serialize(self, db_model_obj):
      attributes = '__public__'
      if self.current_request.user.is_superuser():
          attributes = '__private__'
  
      payload = dict((c, getattr(db_model_obj, c)) 
                     for c in getattr(db_model_obj, attributes))
  
      return self.serialization_strategy.execute(payload)
  </code></pre>
  
  <p>Thoughts on this approach's readability and clarity? Is this a pythonic approach to the problem?</p>
  
  <p>Thanks in advance.</p>