django-formapi 0.2.0
Django API creation with signed requests utilizing forms for validation.
License: MIT
Keywords: django,formapi,api,rpc,signed,request,form,validation

django-formapi
==============

Create JSON API:s with HMAC authentication and Django form-validation.

.. image:: https://travis-ci.org/5monkeys/django-formapi.png?branch=master
    :target: http://travis-ci.org/5monkeys/django-formapi
.. image:: https://coveralls.io/repos/5monkeys/django-formapi/badge.png 
    :target: https://coveralls.io/r/5monkeys/django-formapi
.. image:: https://pypip.in/v/django-formapi/badge.png
    :target: https://pypi.python.org/pypi/django-formapi
.. image:: https://pypip.in/d/django-formapi/badge.png
    :target: https://pypi.python.org/pypi/django-formapi
.. image:: https://pypip.in/wheel/django-formapi/badge.png
    :target: https://pypi.python.org/pypi/django-formapi
.. image:: https://pypip.in/egg/django-formapi/badge.png
    :target: https://pypi.python.org/pypi/django-formapi
.. image:: https://pypip.in/license/django-formapi/badge.png
    :target: https://pypi.python.org/pypi/django-formapi
.. image:: https://d2weczhvl823v0.cloudfront.net/5monkeys/django-formapi/trend.png
    :target: https://bitdeli.com/free

Installation
------------

Install django-formapi in your python environment

.. code:: sh

    $ pip install django-formapi

Add ``formapi`` to your ``INSTALLED_APPS`` setting.

.. code:: python

    INSTALLED_APPS = (
        ...
        'formapi',
    )

Add ``formapi.urls`` to your urls.py.

.. code:: python

  urlpatterns = patterns('',
      ...
      url(r'^api/', include('formapi.urls')),
  )

Usage
-----

Go ahead and create a ``calls.py``. 

.. code:: python

  class DivisionCall(calls.APICall):
      """
      Returns the quotient of two integers
      """
      dividend = forms.FloatField()
      divisor = forms.FloatField()
  
      def action(self, test):
          dividend = self.cleaned_data.get('dividend')
          divisor = self.cleaned_data.get('divisor')
          return dividend / divisor

  API.register(DivisionCall, 'math', 'divide', version='v1.0.0')


Just create a class like your regular Django Forms but inheriting from ``APICall``. Define the fields that your API-call
should receive. The ``action`` method is called when your fields have been validated and what is returned will be JSON-encoded
as a response to the API-caller. The ``API.register`` call takes your ``APICall``-class as first argument, the second argument is 
the ``namespace`` the API-call should reside in, the third argument is the ``name`` of your call and the fourth the ``version``. 
This will result in an url in the form of ``api/[version]/[namespace]/[call_name]/`` so we would get ``/api/v1.0.0/math/divide/``.

A valid call with the parameters ``{'dividend': 5, 'divisor': 2}`` would result in this response:

.. code:: javascript

  {"errors": {}, "data": 5, "success": true}

An invalid call with the parameters ``{'dividend': "five", 'divisor': 2}`` would result in this response:

.. code:: javascript

  {"errors": {"dividend": ["Enter a number."]}, "data": false, "success": false}


Authentication
--------------
By default ``APICalls`` have HMAC-authentication turned on. Disable it by setting ``signed_requests = False`` on your ``APICall``.

If not disabled users of the API will have to sign their calls. To do this they need a ``secret`` generate, create a ``APIKey`` through the django
admin interface. On save a personal ``secret`` and ``key`` will be generated for the API-user. 

To build a call signature for the ``DivisonCall`` create a querystring of the calls parameters sorted by the keys ``dividend=5&divisor=2``. Create a HMAC using SHA1 hash function.
Example in python:

.. code:: python
  
  import hmac
  from hashlib import sha1
  hmac_sign = hmac.new(secret, urllib2.quote('dividend=5&divisor=2'), sha1).hexdigest()

A signed request against ``DivisionCall`` would have the parameters ``{'dividend': 5, 'divisor': 2, 'key': generated_key, 'sign': hmac_sign}``

Documentation
-------------
Visit ``/api/discover`` for a brief documentation of the registered API-calls.