django-formapi icon indicating copy to clipboard operation
django-formapi copied to clipboard

Django API creation with signed requests utilizing forms for validation.

django-formapi

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

.. image:: https://travis-ci.com/5monkeys/django-formapi.svg?branch=master :target: http://travis-ci.com/5monkeys/django-formapi .. image:: https://coveralls.io/repos/github/5monkeys/django-formapi/badge.svg?branch=master :target: https://coveralls.io/github/5monkeys/django-formapi?branch=master .. image:: https://badge.fury.io/py/django-formapi.svg :target: https://badge.fury.io/py/django-formapi .. image:: https://img.shields.io/pypi/l/django-formapi.svg :target: https://pypi.python.org/pypi/django-formapi .. image:: https://img.shields.io/pypi/wheel/django-formapi.svg :target: https://pypi.python.org/pypi/django-formapi .. image:: https://img.shields.io/pypi/pyversions/django-formapi.svg :target: https://pypi.python.org/pypi/django-formapi .. image:: https://img.shields.io/pypi/dm/django-formapi.svg :target: https://pypi.python.org/pypi/django-formapi

Version compatibility

See Travis-CI page for actual test results: https://travis-ci.com/5monkeys/django-formapi

====== === Django 3.6 ====== === 3.2 Yes ====== ===

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 = [ ..., 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.