Andoni Rodríguez


Articulos

Django Rest Framework


Tutorial. Cómo crear una API con Django Rest Framework

Según su definición en Wikipedia una API es:

In computer programming, an application programming interface (API) is a set of subroutine definitions, protocols, and tools for building application software. In general terms, it is a set of clearly defined methods of communication between various software components. A good API makes it easier to develop a computer program by providing all the building blocks, which are then put together by the programmer.

El desarrollo de API's se ha convertido en los últimos años en una parte fundamental de la web. Con la aparición de nuevos dispositivos, la necesidad de tener estandarizada y centralizada la forma en la que se consume información, se ha hecho más importante que nunca.

En mi trabajo he tenido la oportunidad de diseñar e implementar una API con Django Rest Framework ha sido una experiencia muy satisfactoria.

En esta ocasión, además de hacer un post explicando cómo montar una API con Django Rest Framework, tambien teneis disponible un pequeño videotutorial.

Herramientas

Las herramientas que vamos a necesitar son las siguientes:

Docker, para poder tener la API totalmente aislada y dentro de un contenedor, la terminal, para lanzar todos los comandos necesarios y PyCharm, que lo vamos a usar como IDE de programación.

Estructura y configuración

Para poder empezar a desarrollar la API necesitamos configurar el proyecto de la siguiente forma:

$ docker-compose run --rm djangorest django-admin.py startproject drf_basics .

Esto generará un proyecto Django llamado 'drf_basics'.

$ docker-compose run --rm djangorest python manage.py startapp superheroes

Posteriormente procedemos a la generación de ficheros para la aplicación, como en este caso va a ser una API de superheroes, lo hemos llamado 'superheroes'.

Después de ejecutar estos comandos, el directorio tendrá el siguiente aspecto:

⇒  ls 
Dockerfile
docker-compose.yml
drf_basics
manage.py
requirements.txt
superheroes

Se puede ver que hay 2 ficheros relacionados con Docker, no los voy a explicar por ser no ser la temática específica del post, pero contienen las definiciones necesarias para que la API pueda funcionar dentro de un contenedor.

Siempre podéis echarle un vistazo a este post sobre funcionamiento de Docker y docker-compose, en el cual hablo ampliamente de estos componentes.

El fichero de 'requirments.txt' es un fichero que contiene la paquetería python necesaria para que el proyecto pueda funcionar. Los únicos paquetes que necesita la API son 'django' y el propio 'djangorestframework'.

django
djangorestframework

Configuración del proyecto

Dentro del directorio 'drf_basics/settings.py' tenemos que agregar las siguientes líneas en la sección 'INSTALLED_APPS' para que el proyecto Django sepa qué módulos estamos usando:

    'rest_framework',
    'superheroes.apps.SuperheroesConfig'

'INSTALLED_APPS' quedaría de esta forma:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'superheroes.apps.SuperheroesConfig'
]

Modelos

Los modelos mapean tablas de bases de datos en objetos Django. Para crearlos nos vamos al fichero 'models.py' dentro del directorio 'superheroes' y agregamos lo siguiente:

class Publisher(models.Model):
    name = models.CharField(max_length=100, blank=True, default='')
    founder = models.CharField(max_length=100, blank=True, default='')

    class Meta:
        ordering = ('name',)


class SuperHeroe(models.Model):
    name = models.CharField(max_length=100, blank=True, default='')
    gender = models.CharField(max_length=100, blank=True, default='')
    real_name = models.CharField(max_length=100, blank=True, default='')
    publisher = models.ForeignKey(Publisher)

    class Meta:
        ordering = ('name',)

Con esto ya tenemos creados los modelos.

Para generar estos modelos en base de datos tenemos que lanzar los siguientes comandos:

$ docker-compose run --rm djangorest python manage.py makemigrations superheroes

Que generará un fichero de 'migrations' con los modelos. Y posteriormente:

$ docker-compose run --rm djangorest python manage.py migrate

Que aplicará el fichero de migrations a una db sqlite3.

Serializers

Los serializers son la forma que tiene Django Rest de representar y validar los modelos en forma de objetos JSON.

Necesitamos crear un fichero 'serializers.py' dentro del directorio 'superheroes' y agregar las siguientes líneas:

class SuperHeroeSerializer(serializers.ModelSerializer):
    class Meta:
        model = SuperHeroe
        fields = ('id', 'name', 'gender', 'real_name', 'publisher')

class PublisherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publisher
        fields = ('id', 'name', 'founder')

Con esto los serializers estarían listos.

Probando modelos/serializers

Con los modelos y serializers creados podemos ir a la consola de python y agregar los primeros datos a la API.

Para acceder a la consola de python hacemos lo siguiente:

$ docker-compose run --rm djangorest python manage.py shell

Agregamos los primeros modelos de la siguiente forma:

from superheroes.models import Publisher, SuperHeroe
from superheroes.serializers import PublisherSerializer, SuperHeroeSerializer

marvel = Publisher(name="Marvel Comics", founder="Martin Goodman")
marvel.save()

hulk = SuperHeroe(name="Hulk", gender="male",real_name="Bruce Banner", publisher=marvel)
hulk.save()

Para ver una representación 'JSON' de los modelos basta con llamar a los serializers de la siguiente forma:

serializer = SuperHeroeSerializer(hulk)
serializer.data

Bien, nuestra pequeña base de datos de superheroes empieza a tener sus primeros registros :)

Views

Para poder pedir los datos que nos proporciona la combinación de modelos y serializers, necesitamos views.

En el fichero 'superheroes/views.py' agregamos lo siguiente:

from superheroes.models import SuperHeroe, Publisher
from superheroes.serializers import SuperHeroeSerializer, PublisherSerializer
from rest_framework import generics

class SuperHeroeList(generics.ListCreateAPIView):
    queryset = SuperHeroe.objects.all()
    serializer_class = SuperHeroeSerializer


class SuperHeroeDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = SuperHeroe.objects.all()
    serializer_class = SuperHeroeSerializer


class PublisherList(generics.ListCreateAPIView):
    queryset = Publisher.objects.all()
    serializer_class = PublisherSerializer


class PublisherDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Publisher.objects.all()
    serializer_class = PublisherSerializer

Para las views usamos las 'mixed-in generic views' de Django Rest Framework, son sencillas y nos permiten cubrir todas las necesidades para la API (GET, POST, UPDATE y DELETE).

Routing

Ha llegado la hora de enlazar todas las partes de la API con el routing, para lograr esto primero nos vamos al fichero 'drf_basics/urls.py' e incluimos las rutas de la app 'superheroes' de la siguiente forma:

url(r'^', include('superheroes.urls')),

El fichero debería quedar así:

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('superheroes.urls')),

]

Y en el fichero 'superheores/urls.py':

from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from superheroes import views

urlpatterns = [
    url(r'^superheroe/$', views.SuperHeroeList.as_view()),
    url(r'^superheroe/(?P[0-9]+)/$', views.SuperHeroeDetail.as_view()),
    url(r'^publisher/$', views.PublisherList.as_view()),
    url(r'^publisher/(?P[0-9]+)/$', views.PublisherDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

Los 'urlpatterns' sirven para que Django Rest Framework pueda encontrar las views asociadas a las expresiones regulares definidas.

Bien! Con esto ya tenemos una API totalmente funcional y lista para ser usada.

Probando la API

Arrancamos la API de la siguiente forma:

$ docker-compose up

Si todo ha ido bien deberíamos poder probar la API en la siguientes URL's:

'http://127.0.0.1:8000/superheroe'

SuperHeroe API browseable

O 'http://127.0.0.1:8000/publisher'

Publisher API browseable

Es muy recomendable explorar las diferentes opciones que da la API navegable de Django Rest Framework.

Si quereis probar los verbos HTTP por terminal, recomiendo la herramienta httpie, para instalarla basta con:

$ pip install httpie

⇒  http --json GET http://127.0.0.1:8000/superheroe/
HTTP/1.0 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Server: WSGIServer/0.1 Python/2.7.13
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

[
    {
        "gender": "male",
        "id": 1,
        "name": "Hulk",
        "publisher": 1,
        "real_name": "Bruce Banner"
    },
    {
        "gender": "male",
        "id": 2,
        "name": "Iron Man",
        "publisher": 1,
        "real_name": "Tony Stark"
    }
]

De esta forma podemos probar en la terminal sin tener que recurrir al navegador.

Conclusiones

Es cierto que Django Rest Framework puede parecer al principio un poco complicado, pero a medida que se va ganando soltura esta sensación va desapareciendo.

Siempre podéis echarle un vistazo al proyecto en GitHub y hacer las pruebas que queráis.

Espero que tanto el post como el videotutorial le puedan servir a alguien que quiera iniciarse en Django Rest Framework.

Un saludo.