REST API Framework. Modular, extendible and addressing lots of the limitations that I came across using other frameworks.
- Base and Model handlers
- CRUD operations
- Accepts
application/json
andapplication/x-www-form-urlencoded
content-type and returns JSON - Request-level field selection
- Multiple authentication methods
- Multiple handlers should be able to to serve the same resource, with each using a different authentication method.
- Ordering, slicing, filtering
- ModelHahdler should be able to output fake fields. Static model related data can be
added by using properties. Dynamic model related data can be added by
using the handler's
inject_data_hook
method, which, since is a handler method, is aware of the request context. - Enable/disable Plural-PUT and Plural-DELETE explicitly.
- View that handles login with username/password and returns JWT token
- Emails upon crashes
- Excel serialization
- Rename methods that should be renamed. Methods that return something should
be named
get-<something>
. Others should be namedset-<something>
. - Be able to exclude model fields from validation and cleaning
- Check all TODOs in the code
- Make sure code is succinct and it's flow is understandable.
- Flexible way to add headers and specify status codes to responses
- http://pycallgraph.slowchop.com/en/master/index.html
- 100% test coverage
- Rate limiting
- PEP8
-
django-firestone
makes use of class based-views. This means that: -
API Handlers are modular and very easily testable
-
Every step in the request data flow, from start to finish, can be easily overridden and extended.
-
They inherit from each other, and therefore reduce boilerplate code
-
Multiple handlers can be assigned per resource type, with each handler being responsible for a specific authentication mechanism. This way multiple control flow statements and spaghetti code in the handlers is avoided.
-
Every handler specifies the representation of its own response, including that of nested fields, regardless of how deep they appear.
I initially started building django-firestone
on top of Django's generic
CBVs. Even though these are indeed very powerful and cover various use cases,
have proven to be very inflexible. They enforce a very fixed data flow, which
didn't suit the architecture of django-firestone
at all.
Take the following example:
I needed a very generic proxy view to perform some checks and then invoke the real view (which I will call
handler
from now on) for all the request processing. However, thedispatch
method of Django's generic class-based views wants to immediately call the view method corresponding to the HTTP request method. In my case, this method would live in the handler, and not in the view. Yes, I could overridedjango.views.generic.base.View.dispatch
, but that would basically mean that I override the whole logic of Django's generic CBVs. So I chose to start from scratch; Same paradigm, different logic and implementation.
The use of proxy views, allows django-firestone
to select the correct
handler based on the authentication method that a request uses. This makes
for way cleaner handler code, without any flow control checks that would
otherwise be needed.
Need to expose a model resource, using multiple authentication methods? You'd
then need create as many handlers, with each one responsible for each
authentication method.
- Python 2.7
- Django 1.5.4 or later
request --> URL Mapper invokes the corresponding proxy view based on the URL
Proxy view --> invokes the corresponding handler, based on the request's authentication method
Handler --> Executes the request and returns an HTTPResponse object to the proxy view
Proxy view --> Returns the HttpResponse object
The handler parameter authentication
defines the authentication method used
for that particular handler class. The authentication method can be any of the
mixins defined in the firestone.authentication
module.
While the authentication method is defined as a handler class attribute, behind the scenes it's set as a handler class mixin, therefore the handler class inherits its funcionality.
The API handler is open and allows all incoming requests
The API handler only allows requests with a valid session ID
The API handler only allows requests that carry a valid signature
The API handler only allows requests that carry a valid Authentication: JWT <token>
header.
A Token can be issued using the itsdangerous
library, upon correct user
login. You can directly use the
firestone.example_handlers.ObtainJWTHandler
, or even modify/extend it.
Once you login and obtain a JWT token, you can use the token in the
Authorization
request header for any handler that uses JWT Authentication, as:
Authorization: JWT <token>
In case you'd like to modify how a user is identified and the request.user
parameter is set, for handlers using JWT Authentication, override handler
method verify_request_user(payload)
.
Provide a few links that explain it well. How to customize behavior. Which HTTPS it's rock solid, and has many benefits compared to sesssions.
field
, for field selectionorder
, for orderingpage
,ipp
(items per page) for paging
TODO
Initiated by the order=
querystring parameter. It only makes sense for
plural GET, plural PUT and plural DELETE requests. For all other requests it's
ignored.
Initiated by the page=
querystring parameter. The ipp=
querystring
parameters indicates the items per page. If not given, the handler's default
items_per_page
attribute is used.
It only makes sense on requests that return a list of data, and for all other
requests is ignored.
Pagination is performed after the action takes place, and this is mainly the reason that it should never raise an error. In that case, the resources modified/created would be hidden from the response.
Careful, for requests like a plural DELETE, plural PUT, or bulk POST, pagination can be confusing, since it could hide part of the resources that have been created/deleted/updated.
virtualenv folder --no-site-packages
cd folder
source bin/activate
git clone git@github.com:stargazer/django-firestone.git
cd django-firestone
python setup.py install
python setup.py test
coverage run setup.py test
coverage html
./manage.py <management command>
either run:
pip install django-firestone
or include in the requirements of your project django-firestone
The testproject
package contains a mini Django application built on top of
django-firestone
. The test project is mainly used to initiate
django-firestone
's test suite
Clone django-firestone
git clone git@github.com:stargazer/django-firestone.git
Install tox and run
pip install tox coverage
cd django-firestone
tox
This will run the whole testing suite, accounting for various combinations of Python and Django versions
# handlers.py
from firestone import ModelHandler
from authentication import SessionAuthentication, NoAuthentication
class UserHandlerSessionAuth(ModelMandler):
"""
This handler will take over requests carrying a Django session
"""
model = User
authentication = SessionAuthentication
http_methods = ['GET', 'POST']
class UserHandlerNoAuth(ModelHandler):
"""
This handler will take over non-authenticated requests
"""
model = User
authentication = NoAuthentication
http_methods = ['GET',]
# urls.py
from django.conf.urls import *
from firestone.proxy import Proxy
from handlers import UserHandlerSessionAuth, UserHandlerNoAuth
userhandler_proxy = Proxy(UserHandlerSessionAuth, UserHandlerNoAuth)
urlpatterns = patterns('',
url(r'^users/$', userhandler_proxy),
)
- Authentication - More authentication methods
- Errors - Clear and readable error messages
- Serialization - Every handler is solely responsible for the representation of its own output. That includes nested data structures, no matter how deeply nested they are
- Lots of handlers can be declared per resource, with each one responsible for one auth method. This greatly reduces control flow statements on application level
- Allowed request body fields for POST and PUT requests can be specified differently