django-rester

Django REST Helper

View project on GitHub

Django-Rester

build codacy pypi license

Package for creating API with built-in validation and authentication

This product is designed to build API endpoints of varying complexity and nesting.

The core is a view class - BaseApiView (the inheritor of the standard django view)


1. requirements
  1. Python 3+

  2. Django 1.11+


2. settings

DEFAULT settings (may be overridden):

DJANGO_RESTER = {
    'AUTH_BACKEND': 'django_rester.rester_jwt', 
    'RESPONSE_STRUCTURE': False,
    'CORS_ACCESS': False,
    'FIELDS_CHECK_EXCLUDED_METHODS': ['OPTIONS', 'HEAD'],
    'SOFT_RESPONSE_VALIDATION': False, 
}

DJANGO_RESTER_JWT: {
    'SECRET': 'secret_key',
    'EXPIRE': 60 * 60 * 24 * 14,  # seconds
    'AUTH_HEADER': 'Authorization',
    'AUTH_HEADER_PREFIX': 'jwt',
    'ALGORITHM': 'HS256',
    'PAYLOAD_LIST': ['username'],
    'USE_REDIS': False,  # here can be an int value (redis db number)
    'LOGIN_FIELD': 'username', # as default django login field
}

DJANGO_RESTER - django-rester settings:

     AUTH_BACKEND - authentication backend*

     RESPONSE_STRUCTURE - Either False or a dict with ‘success’, ‘message’ and ‘data’ as a values

     CORS_ACCESS - CORS control: True, False, ‘*’, hosts_string

     FIELDS_CHECK_EXCLUDED_METHODS - methods, which will not be processed with body structure checks

     SOFT_RESPONSE_VALIDATION - if True, response will not be cut off if it will contain additional to response_structure fields

DJANGO_RESTER_JWT - JWT authentication settings (in case of ‘RESTER_AUTH_BACKEND’ = ‘django_rester.rester_jwt’)*:

     SECRET - JWT secret key

     EXPIRE - token expiration time (datetime.now() + RESTER_EXPIRATION_DELTA)

     AUTH_HEADER - HTTP headed, which will be used for auth token.

     AUTH_HEADER_PREFIX - prefix for auth token (“Authorization:<prefix> <token>”)

     ALGORITHM - cypher algorithm

     PAYLOAD_LIST - payload list for token encode (will take specified user attributes to create token)

     USE_REDIS - use redis-server to store tokens or not

     LOGIN_FIELD - user login field (default is ‘username’ as in django) ***

3. built-in statuses

from django_rester.status import ...


slightly modified status.py from DRF, it’s simple and easy to understand.

Any statuses used in this documentation are described in that file. ***

4. built-in exceptions:

from django_rester.exceptions import ...


Exceptions, which will help you to recognise errors related to django-rester

class ResterException(Exception)

    base django-rester exception, standard Exception inheritor

class ResponseError(Exception)

    ResponseError inheritor, added response status - HTTP_500_INTERNAL_SERVER_ERROR

class ResponseBadRequest(ResponseError)

    ResponseError inheritor, response status changed to HTTP_400_BAD_REQUEST

class ResponseServerError(ResponseError)

    ResponseError inheritor

class ResponseAuthError(ResponseError)

    ResponseError inheritor, response status changed to HTTP_401_UNAUTHORIZED

class ResponseOkMessage(ResponseError)

    ResponseError inheritor

    acceptable arguments: *, message=’’, data=None, status=HTTP_200_OK

class ResponseFailMessage(ResponseError)

    ResponseError inheritor

    acceptable arguments: *, message=’’, data=None, status=HTTP_500_INTERNAL_SERVER_ERROR

class ResponseBadRequestMsgList(ResponseError)

    ResponseError inheritor

    acceptable arguments: *, messages=None, status=HTTP_400_BAD_REQUEST

    messages could be list, tuple or string.

class JSONFieldError(ResterException)

    ResterException inheritor, base JSONField exception

class JSONFieldModelTypeError(JSONFieldError)

    JSONField exception, raises when type of model parameter is not valid

class JSONFieldModelError(JSONFieldError)

    JSONField exception, raises when value of model parameter is not valid

class JSONFieldTypeError(JSONFieldError)

    JSONField exception, simple TypeError inside JSONField class

class JSONFieldValueError(JSONFieldError)

    JSONField exception, simple ValueError inside JSONField class

class BaseAPIViewException(Exception)

    BaseAPIView exception class

class RequestStructureException(BaseAPIViewException)

    raise if request structure is invalid

class ResponseStructureException(RequestStructureException)

    raise if response structure is invalid ***

5. permission classes

from django_rester.permission import ...


Permission classes created to interact wih @permissions() decorator (good example of usage), or in any other way you want

All permission classes accepts only one argument on init - django view request object.

All permission classes has 2 attributes, defined on init:

check: Bool - returns True or False if request.user may or may not access endpoint method

message: could be a string or list of messages


class BasePermission

    contains all base permission methods, it is not recommended to use it directly in projects

class IsAuthenticated(BasePermission)

    check = True if user authenticated and active, else False

class IsAdmin(BasePermission)

    check = True if user authenticated and active and is_superuser, else False

class AllowAny(BasePermission)

    check = True for any user (even anonymous)


6. built-in decorators

from django_rester.decorators import ...


@permissions()

    accepts permission class or list, tuple of classes.

    if check is passed, then user will be allowed to use endpoint

example:

class Example(BaseApiView):

    @permissions(IsAdmin)
    def post(request, request_data, *args, **kwargs):
        pass

7. built-in views

from django_rester.views import ...


class BaseApiView(View)

inherits from standard django view.

class attributes:

    auth - authentication backend instance

    request_fields - request validator (use JSONField to build this validator)

    response_fields - response validator (use JSONField to build this validator)


class HTTP methods (get, post, put, etc…) accepts next arguments: request, request_data, *args, **kwargs

    request - standard django view request object

    request_data - all received request parameters as json serialized object

User authentication with selected authentication backend


class Login(BaseApiView)

Could be used to authenticate user with selected authentication backend.

    Allowed method is ‘POST’ only.

    Requires username and password in request parameters (username fieldname parameter may be set in settings)

    Returns token and HTTP_200_OK status code if authentication success, error message and HTTP_401_UNAUTHORIZED if failed


class Logout(BaseApiView)

Could be used to logout (with redis support) or just to let know frontend about logout process.


Any view could be used the same way, here is a simple example:

    app/views.py:

from django_rester.views import BaseAPIView
from django_rester.decorators import permissions
from django_rester.exceptions import ResponseOkMessage
from django_rester.permission import IsAdmin
from django_rester.status import HTTP_200_OK
from app.models import Model # import Model from your application
from django_rester.fields import JSONField

class TestView(BaseAPIView):

    request_fields = {"POST": {
        "id": JSONField(field_type=int, required=True, ),
        "title": JSONField(field_type=str, required=True, default='some_title'),
        "fk": [{"id": JSONField(field_type=int, required=True)}],
    }}

    response_fields = {"POST": {
        "id": JSONField(field_type=int, required=True, ),
        "title": JSONField(field_type=str, required=True, default='some_title'),
        # ...
    }}
    
    def retrieve_items():
        return Model.objects.all()

    def create_item(title):
        item, cre = Model.objects.get_or_create(title=title)
        return item, cre

    @permissions(AllowAny)
    def get(self, request, request_data, *args, **kwargs):
        items = self.retrieve_items()
        response_data = {...here we should build some response structure...}***
        return response_data, HTTP_200_OK

    @permissions(IsAdmin)
    def post(self, request, request_data, *args, **kwargs):
        title = request_data.get('title', None)
        # no need to check 'if title', because it is allready validated by 'available_fields'
        # ... here we will do some view magic with the rest request_data
        item, cre = self.create_item(title)
        if not cre:
            raise ResponseOkMessage(message='Item allready exists', data={'title': title})
        response_data = {...here we should build some response structure...}***

        return response_data

    app/urls.py:

from django.conf.urls import url
from .views import TestView

urlpatterns = [
    url(r'^test/', TestView.as_view()),
]

8. built-in fields

from django_rester.fields import ...


class JSONField

class attributes:

    field_type - data type (int, float, str, bool)

    required - field is required

    default - default value if not specified

    blank - may or may not be blank

    model - model for foreign relations

    field - field for foreign relations

methods (public), with normal usage, you won’t need them in your code:

    check_type - validate type of JSONField value

    validate - validate field value with parameters ***

*- There is only one authentication backend available for now - RESTER_JWT

**- BaseApiView is on active development stage, other attributes and methods could be added soon

***- automatic response structure build - one of the nearest tasks

Installation notes

pycurl (Mac OS)
brew remove curl
brew install curl-openssl
export PYCURL_SSL_LIBRARY=openssl
pip install --no-cache-dir --global-option=build_ext --global-option="-L/usr/local/opt/openssl/lib" --global-option="-I/usr/local/opt/openssl/include" --compile --install-option="--with-openssl" pycurl