jfinkels/flask-restless — pull request #82 by mkuprionis (2012-07-21 09:17:42+00:00)
Title: Provide extension hooks in API class

I needed a way to extend and modify default Flask-Restless functionality and came up with this. Basically idea is such:

- Before-action hooks allow more complex permission check and modifying/augmenting request
- After-action hooks allow to modify response
- Any extension hook can abort request or return a completely custom response

I'm not yet entirely sure about API of these hooks. For instance with `_before_post` or `_after_get` is clear enough - pass the model about to be created in case of `POST` and pass model + its data in dict in case of `GET`.

With `_after_search`, `_before_patch`, `_after_patch` is a bit more tricky. Now I think best approach is to pass along as much data as possible and let extending class make sense out of it.

This also makes `post_form_preprocessor` from #74 obsolete.

What do you think?

---

Here's some code from my project in progress (and more examples are in tests):

```python
class ProductAPI(API):
def _before_search(self, data):
if not current_user.isAdmin():
if not data.has_key('filters'):
data['filters'] = []
data['filters'].append({
'name': 'sysUserId',
'op': 'equals',
'val': current_user.id
})
return True

def _before_post(self, model):
model.sysUserId = current_user.id

if current_user.isUser():
model.reviewPending = True

return True

class UserAPI(API):

def _before_post(self, model):
model.password = hashlib.md5(model.password + config.SALT).hexdigest()
return True

manager = APIManager(app, session=session)
manager.create_api(
User,
methods=['GET', 'POST', 'PUT', 'DELETE'],
api_class=UserAPI)

manager.create_api(
Product,
methods=['GET', 'POST', 'PUT', 'DELETE'],
api_class=ProductAPI)
```

This change would also allow to address #2 rather elegantly. E.g.:

```python
# views.API
def get(self, instid, **kwargs):
<...>
self._search(**kwargs)
<...>

def _search(self, **kwargs):
<...>
self._before_search(data, **kwargs)
<...>

# Extending class
class ItemAPI(API):
def _before_search(data, user_id):
data['filters'].append({
'name': 'owner_id',
'op': 'equals',
'val': user_id
})
return True

# Actual API
manager.create_api(
Item,
methods=['GET', 'POST', 'PUT', 'DELETE'],
api_class=ItemAPI,
collection_name='/user//items')
```