Package: django-yapi
YAPI == Yet/Why Another API FrameworkThis is a mini-framework for creating RESTful APIs in Django.InstallationDownload dependencies:Python 2.6+Django 1.5+pip installdjango-yapioreasy_installdjango-yapiConfigurationsettings.pyAdd “yapi” to your INSTALLED_APPS setting like this:INSTALLED_APPS = (
    # all other installed apps
    'yapi',
)Add logger handler:LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        # all other handlers
        'log_file_yapi': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(os.path.join(os.path.dirname( __file__ ), '..'), 'logs/yapi.log'),
            'maxBytes': '16777216', # 16megabytes
         },
    },
    'loggers': {
        # all other loggers
        'yapi': {
            'handlers': ['log_file_yapi'],
            'propagate': True,
            'level': 'DEBUG',
        }
    }
}Make sure you have a ‘HOST_URL’ setting containing the address in which the app is deployed:HOST_URL ='http://localhost:8000'(example)If you want to use the middleware that enables CORS, you have to configure it by adding the following settings:MIDDLEWARE_CLASSES = (
    ...
    'yapi.middleware.XsSharing'
)

YAPI = {
    ...

    'XS_SHARING_ALLOWED_ORIGINS': '*', # The allowed domains
    'XS_SHARING_ALLOWED_METHODS': ['POST','GET','OPTIONS', 'PUT', 'DELETE'] # ... and methods
}If you wish to disable ENTIRELY (be careful! :P) CSRF Validation, add the following settings:YAPI = {
    ...

    'CSRFValidation': False
}LogsCreate a ‘logs’ folder in your project’s root folder (if you don’t have one already).
Your project folder should look something like this:myproject/
    __init__.py
    settings.py
    urls.py
    wsgi.py
logs/
manage.pyDatabaseRunpython manage.py syncdbto create the yapi models.API NamespaceNow, you will have to decide the URL “namespace” from which your API will be available and add it to
your top-levelurls.py.Yapi’sconventionis that everything that regards to the API (urls, handlers, serializers, etc) should be in a
package named “api” inside the respective app package. This way, the API namespace should point to a urls.py
inside an “api” package in your project’s main package:myapp/
    api/
        __init__.py
        handlers.py
        serializers.py
        urls.py
    __init__.py
    models.py
    urls.py
    views.py
myproject/
    api/
        __init__.py
        urls.py
    __init__.py
    settings.py
    urls.py
    wsgi.py
logs/
manage.pyAdd namespace to the top-levelurls.py:# myproject/urls.py
# ============

urlpatterns = patterns('',
   # all other url mappings
   url(r'^api', include('myproject.api.urls', namespace='api')),
)In this example, we have an app called “myapp” which has an API. In order for it to be “acessible”, its URLs must be
added to the top-level API namespace:# myproject/api/urls.py
# ============

urlpatterns = patterns('',
    # all other api url mappings
    url(r'^/myapp', include('myapp.api.urls', namespace='myapp')),
)ResourcesA “Resource” maps an URL to the code that will handle the requests made to it.By convention, Resource handlers reside in a file calledhandlers.pyin the api package:# myapp/api/handlers.py
# ============

    from yapi.resource import Resource
from yapi.response import HTTPStatus, Response

class ResourceIndex(Resource):
    """
    API endpoint handler.
    """

    # HTTP methods allowed.
    allowed_methods = ['GET']

    def get(self, request):
        """
        Process GET request.
        """

        # Return.
        return Response(request=request,
                        data={ 'hello': 'world' },
                        serializer=None,
                        status=HTTPStatus.SUCCESS_200_OK)Now we map the handler to a given URL:# myapp/api/urls.py
# ============

from django.conf.urls import patterns, url
from yapi.resource import Resource

from handlers import ResourceIndex

urlpatterns = patterns('',
    url(r'^/?$', ResourceIndex.as_view(), name='index'),
)This way, if puthttp://localhost:8000/api/myappin the address bar of your browser, you should get a JSON object
in return containing{ 'hello': 'world' }.Basic SchemaFrom the example above we can see how easy it is to write a Resource class. You just need to set theallowed_methodsarray with the HTTP verbs that the handler supports and then, for each allowed verb, write the respective method.Yapi’sconventionis to use POST/GET/PUT/DELETE to CREATE/READ/UPDATE/DELETE.POST->def post(request)GET->def get(request)PUT->def put(request)DELETE->def delete(request)IMPORTANT:In this example there isn’t any additional value being passed by the URL, therefore the only data received
by the methods is the standard Djangorequest. Make sure to include in the method any other additional parameter
that may be passed by the URL.Authentication & AuthorizationIf the resource should only be accessible via authenticated users, then a variableauthenticationshould be set
with an array of the valid authentication types. Yapi ships with the following authentication methods:yapi.authentication.SessionAuthentication-> Validates if the request is made by a browser with a valid Django session (i.e. user is logged in to the site)yapi.authentication.ApiKeyAuthentication-> Validates if the request is made with a validapi_keyprovided as a GET parameter.When several authentication methods are accepted,the request is considered authenticated as soon as one checks(e.g. SessionAuthentication fails, but APIKeyAuthentication validates). If the user is authenticated, it is added to
therequestobject and can be accessed byrequest.auth['user'].If the resource should only be acessible by authenticated users that match a specifc ruleset, thenpermissionsshould be set with an array of all the authorization credentials required. Yapi ships with the following authorization
methods:yapi.permissions.IsStaff-> Checks if user has Staff permission.In order for the authorization to be validated all authorization classes must check.If we wanted to make the Resource in the example above only available to authenticated staff users, it would look
something like this:# myapp/api/handlers.py
# ============

from yapi.authentication import SessionAuthentication, ApiKeyAuthentication
from yapi.resource import Resource
from yapi.response import HTTPStatus, Response

class ResourceIndex(Resource):
    """
    API endpoint handler.
    """

    # HTTP methods allowed.
    allowed_methods = ['GET']

    # Authentication & Authorization.
    authentication = [SessionAuthentication, ApiKeyAuthentication]
    permissions = [IsStaff]

    def get(self, request):
        """
        Process GET request.
        """

        # Return.
        return Response(request=request,
                        data={ 'hello': 'world' },
                        serializer=None,
                        status=HTTPStatus.SUCCESS_200_OK)Request BodyWhen the request is aPOSTor aPUT, it is assumed that there is a request body and, if it isn’t present or fails
parsing, the request fails.IMPORTANTCurrently, the only format accepted for the request body is a JSON payload.The request body is parsed into a native Pythondictand can be acessible inrequest.data.Resource ListingIn trying to follow some HATEOAS principles, we suggest that the API’s root URL should return a listing of the available
resources and respective URLs:# myproject/api/resources.py
# ============

from django.conf import settings
from django.core.urlresolvers import reverse

def get_api_resources_list(user):
    return {
        'url': settings.HOST_URL + reverse('api:index'),
        'resources': {
            'myapp': {
                'url': settings.HOST_URL + reverse('api:myapp:index')
            }
        }
    }Now, add it to the API’s root URL:# myproject/api/urls.py
# ============

urlpatterns = patterns('',
    # all other api url mappings
    url(r'^/?$', ResourcesListHandler.as_view(), name='index'),
    url(r'^/myapp', include('myapp.api.urls', namespace='myapp')),
)And write the respective handler:# myproject/api/handlers.py
# ============

    from yapi.resource import Resource
from yapi.response import HTTPStatus, Response
from resources import get_api_resources_list

class ResourcesListHandler(Resource):
    """
    API endpoint handler.
    """

    # HTTP methods allowed.
    allowed_methods = ['GET']

    def get(self, request):
        """
        Process GET request.
        """

        # Return.
        return Response(request=request,
                        data=get_api_resources_list(request.auth['user']),
                        serializer=None,
                        status=HTTPStatus.SUCCESS_200_OK)Don’t forget to keep this list updated everytime you make changes to your resources.Responseyapi.response.Responseis the prefered way of returning a call to a given handler (Django’sHTTPResponsealso works)request-> The request that originated this response.data-> The raw response data (a Pythondict, with all data in native types)serializer-> The serializer that will be used to serialize the data.status-> The HTTP status code of the response (preferably fromyapi.response.HTTPStatus)pagination(optional) -> When the response data is a QuerySet, this states if the response should be paginated or not. Default is True.filters(optional) -> When the response data is a QuerySet and it was filtered by given parameters, they are provided in this field.SerializersWhen the responsedatais acomplexPython object, it must first be serialized to native Python types. This way,
each for every resource that may be returned, a serializer that implementsyapi.serializers.BaseSerializermust be
written.Basically, ato_simple(self, obj, user=None)method has to be implemented.obj-> The object instance that will be serialized.user(optional) -> The user that made the request. This is useful when the instance representation varies according to the user/permissions.Lets look at an example for serializing a user:from apps.api.serializers import BaseSerializer

class UserSerializer(BaseSerializer):
    """
    Adds methods required for instance serialization.
    """

    def to_simple(self, obj, user=None):
        """
        Please refer to the interface documentation.
        """
        # Build response.
        simple = {
            'email': obj.email,
            'name': obj.name,
            'last_login': obj.last_login.strftime("%Y-%m-%d %H:%M:%S")
        }

        # Return.
        return simpleIn this case, an example response could be:return Response(request=request,
                data=request.auth['user'],
                serializer=UserSerializer,
                status=HTTPStatus.SUCCESS_200_OK)