Construyendo una API
En el capítulo anterior, construimos un sistema para el registro de estudiantes y la inscripción en los diferentes cursos. Creaste vistas para mostrar el contenido de los cursos y aprendiste a usar el marco de caché de Django.
En este capítulo, crearemos una API RESTful para nuestra plataforma de aprendizaje electrónico. Una API te permite construir un núcleo común que puede ser utilizado en múltiples plataformas como sitios web, aplicaciones móviles, complementos, y más. Por ejemplo, puedes crear una API para ser utilizada por una aplicación móvil para tu plataforma de aprendizaje electrónico. Si proporcionas una API a terceros, podrán consumir información y operar con tu aplicación de forma programática. Una API permite a los desarrolladores automatizar acciones en tu plataforma e integrar tu servicio con otras aplicaciones o servicios en línea. Construiremos una API completamente funcional para la plataforma de aprendizaje electrónico.
En este post, realizaremos lo siguiente:
• Instalar Django REST framework
• Crear serializadores para tus modelos
• Construir una API RESTful
• Crear serializadores anidados
• Construir vistas de API personalizadas
• Manejar autenticación de API
• Agregar permisos a vistas de API
• Crear un permiso personalizado
• Implementar ViewSets y enrutadores
• Usar la biblioteca Requests para consumir la API
Comencemos con la configuración de tu API.
Construyendo una API RESTful
Al construir una API, hay varias formas en las que puedes estructurar sus puntos finales y acciones, pero se recomienda seguir los principios REST. La arquitectura REST proviene de Transferencia de Estado Representacional. Las API RESTful están basadas en recursos; tus modelos representan recursos y los métodos HTTP como GET, POST, PUT o DELETE se utilizan para recuperar, crear, actualizar o eliminar objetos. Los códigos de respuesta HTTP también se utilizan en este contexto. Se devuelven diferentes códigos de respuesta HTTP para indicar el resultado de la solicitud HTTP, por ejemplo, códigos de respuesta 2XX para éxito, 4XX para errores, y así sucesivamente.
Los formatos más comunes para intercambiar datos en API RESTful son JSON y XML. Construiremos una API RESTful con serialización JSON para nuestro proyecto. Tu API proporcionará las siguientes funcionalidades:
• Recuperar materias
• Recuperar cursos disponibles
• Recuperar contenido del curso
• Inscribirse en un curso
Puedes construir una API desde cero con Django creando vistas personalizadas. Sin embargo, hay varios módulos de terceros que simplifican la creación de una API para tu proyecto; el más popular entre ellos es Django REST framework.
Instalando Django REST framework
Django REST framework te permite construir fácilmente APIs RESTful para tu proyecto. Puedes encontrar toda la información sobre el framework REST en https://www.django-rest-framework.org/.
Abre la terminal e instala el framework con el siguiente comando:
pip install djangorestframework
Edita el archivo settings.py del proyecto educa y agrega rest_framework al ajuste INSTALLED_APPS para activar la aplicación, de la siguiente manera:
INSTALLED_APPS = [
# ...
'rest_framework',
]
Luego, agrega el siguiente código al archivo settings.py:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
Puedes proporcionar una configuración específica para tu API utilizando el ajuste REST_FRAMEWORK. El framework REST ofrece una amplia gama de ajustes para configurar comportamientos predeterminados. El ajuste DEFAULT_PERMISSION_CLASSES especifica los permisos predeterminados para leer, crear, actualizar o eliminar objetos. Has establecido DjangoModelPermissionsOrAnonReadOnly como la única clase de permiso predeterminada. Esta clase se basa en el sistema de permisos de Django para permitir a los usuarios crear, actualizar o eliminar objetos mientras proporciona acceso de solo lectura para usuarios anónimos. Aprenderás más sobre los permisos más adelante, en la sección Agregar permisos a las vistas.
Para obtener una lista completa de los ajustes disponibles para el framework REST, puedes visitar https://www.django-restframework.org/api-guide/settings/.
Definición de serializadores
Después de configurar el framework REST, necesitas especificar cómo se serializarán tus datos. Los datos de salida deben serializarse en un formato específico, y los datos de entrada se deserializarán para su procesamiento. El framework proporciona las siguientes clases para construir serializadores para objetos individuales:
• Serializer: Proporciona serialización para instancias de clases normales de Python
• ModelSerializer: Proporciona serialización para instancias de modelos
• HyperlinkedModelSerializer: Lo mismo que ModelSerializer, pero representa relaciones entre objetos con enlaces en lugar de claves primarias
Construyamos nuestro primer serializador. Crea la siguiente estructura de archivos dentro del directorio de la aplicación de courses:
api/
__init__.py
serializers.py
Construirás toda la funcionalidad de la API dentro del directorio api para mantener todo bien organizado. Edita el archivo serializers.py y agrega el siguiente código:
from rest_framework import serializers
from courses.models import Subject
class SubjectSerializer(serializers.ModelSerializer):
class Meta:
model = Subject
fields = ['id', 'title', 'slug']
Este es el serializador para el modelo Subject. Los serializadores se definen de manera similar a las clases Form y ModelForm de Django. La clase Meta te permite especificar el modelo a serializar y los campos que se incluirán para la serialización. Todos los campos del modelo se incluirán si no estableces un atributo fields.
Vamos a probar el serializador. Abre la línea de comandos y comienza el shell de Django con el siguiente comando:
python manage.py shell
Ejecuta el siguiente código:
>>> from courses.api.serializers import SubjectSerializer
>>> subject = Subject.objects.latest('id')
>>> serializer = SubjectSerializer(subject)
>>> serializer.data
{'id': 4, 'title': 'Programación', 'slug': 'programacion'}
Entendiendo los parsers y renderizadores
Los datos serializados tienen que ser renderizados en un formato específico antes de devolverlos en una respuesta HTTP. De igual manera, cuando recibes una solicitud HTTP, debes analizar los datos entrantes y deserializarlos antes de poder operar con ellos. El framework REST incluye renderizadores y parsers para manejar eso.
Veamos cómo analizar los datos entrantes. Ejecuta el siguiente código en el shell de Python:
>>> from io import BytesIO
>>> from rest_framework.parsers import JSONParser
>>> data = b'{"id":4,"title":"Programming","slug":"programming"}'
>>> parsed_data = JSONParser().parse(BytesIO(data))
>>> print(parsed_data)
{'id': 4, 'title': 'Programming', 'slug': 'programming'}
Dado un input de cadena JSON, puedes utilizar la clase JSONParser proporcionada por el framework REST para convertirla en un objeto Python.
El framework REST también incluye clases de renderizadores que te permiten formatear las respuestas de la API. El framework determina qué renderizador utilizar a través de la negociación de contenido, inspeccionando el encabezado Accept de la solicitud para determinar el tipo de contenido esperado para la respuesta. Opcionalmente, el renderizador se determina por el sufijo de formato de la URL. Por ejemplo, la URL http://127.0.0.1:8000/api/data.json podría ser un punto final que activa el JSONRenderer para devolver una respuesta JSON.
Vuelve al shell y ejecuta el siguiente código para renderizar el objeto serializador del ejemplo anterior:
>>> from rest_framework.renderers import JSONRenderer
>>> JSONRenderer().render(parsed_data)
Verás la siguiente salida:
b'{"id":4,"title":"Programming","slug":"programming"}'
Utilizas JSONRenderer para renderizar los datos serializados en formato JSON. Por defecto, el framework REST utiliza dos renderizadores diferentes: JSONRenderer y BrowsableAPIRenderer. Este último proporciona una interfaz web para navegar fácilmente por tu API. Puedes cambiar las clases de renderizador predeterminadas con la opción DEFAULT_RENDERER_CLASSES del ajuste REST_FRAMEWORK.
Puedes encontrar más información sobre renderizadores y parsers en los siguientes enlaces:
- Renderizadores: [https://www.django-rest-framework.org/api-guide/renderers/](https://www.django-rest-framework.org/api-guide/renderers/)
- Parsers: [https://www.django-rest-framework.org/api-guide/parsers/](https://www.django-rest-framework.org/api-guide/parsers/)
A continuación, veremos cómo construir vistas de API y utilizar serializadores en las vistas.
Construyendo vistas de lista y detalle
El framework REST viene con un conjunto de vistas genéricas y mixins que puedes utilizar para construir tus vistas de API. Proporcionan la funcionalidad para recuperar, crear, actualizar o eliminar objetos del modelo. Puedes ver todos los mixins y vistas genéricas proporcionadas por el framework REST en [https://www.django-rest-framework.org/api-guide/generic-views/](https://www.django-rest-framework.org/api-guide/generic-views/).
Vamos a crear vistas de lista y detalle para recuperar objetos de Subject. Crea un nuevo archivo dentro del directorio courses/api/ y nómbralo views.py. Agrega el siguiente código a él:
Elearning/educa/courses/api/views.py
from rest_framework import generics from courses.models import Subject from courses.api.serializers import SubjectSerializer class SubjectListView(generics.ListAPIView): queryset = Subject.objects.all() serializer_class = SubjectSerializer class SubjectDetailView(generics.RetrieveAPIView): queryset = Subject.objects.all() serializer_class = SubjectSerializer
En este código, estás utilizando las vistas genéricas ListAPIView y RetrieveAPIView del framework REST. Incluyes un parámetro de URL pk para la vista de detalle para recuperar el objeto para la clave primaria dada. Ambas vistas tienen los siguientes atributos:
- queryset: El QuerySet base que se utilizará para recuperar objetos.
- serializer_class: La clase para serializar objetos.
Ahora agreguemos patrones de URL para tus vistas. Crea un nuevo archivo dentro del directorio courses/api/, nómbralo urls.py y déjalo de la siguiente manera:
Elearning/educa/courses/api/urls.py
from django.urls import path from . import views app_name = 'courses' urlpatterns = [ path('subjects/', views.SubjectListView.as_view(), name='subject_list'), path('subjects/<pk>/', views.SubjectDetailView.as_view(), name='subject_detail'), ]
Edita el archivo principal urls.py del proyecto educa e incluya los patrones de la API de la siguiente manera:
urlpatterns = [
# ...
path('api/', include('courses.api.urls', namespace='api')),
]
Con esto, nuestra API está lista para ser utilizada.
Utilizando el API.
Usa el espacio de nombres 'api' para las URL de tu API. Asegúrate de que tu servidor esté en funcionamiento con el siguiente comando:
python manage.py runserver
y que tienes en ejecución el docker del cache que hayas utilizado previamente, en el post previo.
Vamos a usar curl para utilizar la API. curl es una herramienta de línea de comandos que te permite transferir datos hacia y desde un servidor. Si estás usando Linux, macOS o Windows 10/11, es muy probable que curl esté incluido en tu sistema. Sin embargo, también puedes descargar curl desde https://curl.se/download.html.
Abre el terminal y recupera la URL http://127.0.0.1:8000/api/subjects/ con curl, de la siguiente manera:
curl http://127.0.0.1:8000/api/subjects/
Recibirás una respuesta similar a la siguiente:
[{"id":3,"title":"Física","slug":"fisica"},{"id":1,"title":"Matemáticas","slug":"matematicas"},{"id":2,"title":"Música","slug":"musica"},{"id":4,"title":"Programación","slug":"programacion"}]
Para obtener una respuesta JSON más legible y bien indentada, puedes usar curl con la utilidad json_pp, de la siguiente manera:
curl http://127.0.0.1:8000/api/subjects/ | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 195 100 195 0 0 3058 0 --:--:-- --:--:-- --:--:-- 3421 [ { "id" : 3, "slug" : "fisica", "title" : "Física" }, { "id" : 1, "slug" : "matematicas", "title" : "Matemáticas" }, { "id" : 2, "slug" : "musica", "title" : "Música" }, { "id" : 4, "slug" : "programacion", "title" : "Programación" } ]
La respuesta HTTP contiene una lista de objetos Subject en formato JSON.
En lugar de curl, también puedes usar cualquier otra herramienta para enviar solicitudes HTTP personalizadas, incluida una extensión del navegador como Postman, que puedes obtener en https://www.getpostman.com/.
Abre http://127.0.0.1:8000/api/subjects/ en tu navegador. Verás la API navegadora del marco REST de la siguiente manera:
Esta interfaz HTML es proporcionada por el renderizador BrowsableAPIRenderer. Muestra los encabezados y el contenido del resultado, y te permite realizar solicitudes. También puedes acceder a la vista detallada de la API para un objeto Subject incluyendo su ID en la URL.
Abre http://127.0.0.1:8000/api/subjects/1/ en tu navegador. Verás un único objeto Subject renderizado en formato JSON.
Crear serializadores anidados
Vamos a crear un serializador para el modelo Course. Edita el archivo api/serializers.py de la aplicación courses y agrega el siguiente código:
from courses.models import Subject, Course
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ['id', 'subject', 'title', 'slug', 'overview', 'created', 'owner',
'modules']
Veamos cómo se serializa un objeto Course. Abre la terminal y ejecuta el siguiente comando:
python manage.py shell
Ejecuta el siguiente código:
>>> from rest_framework.renderers import JSONRenderer
>>> from courses.models import Course
>>> from courses.api.serializers import CourseSerializer
>>> course = Course.objects.latest('id')
>>> serializer = CourseSerializer(course)
>>> JSONRenderer().render(serializer.data)
b'{"id":5,"subject":1,"title":"Matem\xc3\xa1ticas Discretas.",
"slug":"matematicas-discretas",
"overview":"curso de matem\xc3\xa1ticas discretas aplicadas a la inform\xc3\xa1tica."
,"created":"2024-03-07T20:37:12.985403+01:00","owner":2,"modules":[5,6]}'
Obtendremos un objeto JSON con los campos que incluimos en CourseSerializer. Puedes ver que los objetos relacionados del gestor de módulos están serializados como una lista de claves primarias, de la siguiente manera:
"modules": [6, 7, 9, 10] Quieres incluir más información sobre cada módulo, así que necesitas serializar los objetos de módulo y anidarlos. Modifica el código anterior del archivo api/serializers.py de la aplicación de cursos para que se vea de la siguiente manera:Elearning/educa/courses/api/serializers.py
from rest_framework import serializers from courses.models import Subject, Course, Module class SubjectSerializer(serializers.ModelSerializer): class Meta: model = Subject fields = ['id', 'title', 'slug'] class ModuleSerializer(serializers.ModelSerializer): class Meta: model = Module fields = ['order', 'title', 'description'] class CourseSerializer(serializers.ModelSerializer): modules = ModuleSerializer(many=True, read_only=True) class Meta: model = Course fields = ['id', 'subject', 'title', 'slug', 'overview', 'created', 'owner', 'modules']
b'{"id":5,"subject":1,"title":"Matem\xc3\xa1ticas Discretas.",
"slug":"matematicas-discretas","overview":"curso de matem\xc3\xa1ticas discretas
aplicadas a la inform\xc3\xa1tica.","created":"2024-03-07T20:37:12.985403+01:00",
"owner":2,
"modules":[
{
"order":0,
"title":"Teoria de la informaci\xc3\xb3n",
"description":"cuantificaci\xc3\xb3n de la informaci\xc3\xb3n"
},
{
"order":1,
"title":"L\xc3\xb3gica",
"description":"L\xc3\xb3gica matem\xc3\xa1tica"}
]}'
Construyendo vistas de API personalizadas
Elearning/educa/courses/api/serializers.py
from django.shortcuts import get_object_or_404 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import generics from courses.models import Subject, Course from courses.api.serializers import SubjectSerializer #... class CourseEnrollView(APIView): def post(self, request, pk, format=None): course = get_object_or_404(Course, pk=pk) course.students.add(request.user) return Response({'enrolled': True})
La vista CourseEnrollView maneja la inscripción de los usuarios en los cursos. El código precedente es el siguiente:
- 1.- Creas una vista personalizada que hereda de APIView.
- 2.- Defines un método post() para acciones POST. No se permitirá ningún otro método HTTP para esta vista.
- 3.- Esperas un parámetro de URL pk que contiene el ID de un curso. Recuperas el curso mediante el parámetro pk dado y lanzas una excepción 404 si no se encuentra.
- 4.- Añades el usuario actual a la relación muchos a muchos de estudiantes del objeto Curso y devuelves una respuesta exitosa.
- Edita el archivo api/urls.py y añade el siguiente patrón de URL para la vista CourseEnrollView:
path('courses/<pk>/enroll/',
views.CourseEnrollView.as_view(),
name='course_enroll'),
Teóricamente, ahora podrías realizar una solicitud POST para inscribir al usuario actual en un curso. Sin embargo, necesitas ser capaz de identificar al usuario y prevenir que los usuarios no autenticados accedan a esta vista. Veamos cómo funcionan la autenticación y los permisos en la API.
Manejando la Autenticación.
Elearning/educa/courses/api/views.py
# ...
from rest_framework.authentication import BasicAuthentication
class CourseEnrollView(APIView):
authentication_classes = [BasicAuthentication]
# ...
Agregando permisos a las vistas
Elearning/educa/courses/api/views.py
# ... from rest_framework.authentication import BasicAuthentication from rest_framework.permissions import IsAuthenticated class CourseEnrollView(APIView): authentication_classes = [BasicAuthentication] permission_classes = [IsAuthenticated] # ...
Has incluido el permiso IsAuthenticated. Esto evitará que los usuarios anónimos accedan a la vista. Ahora puedes realizar una solicitud POST a tu nuevo método de API.
Asegúrate de que el servidor de desarrollo esté en ejecución. Abre la terminal y ejecuta el siguiente comando:
curl -i -X POST http://127.0.0.1:8000/api/courses/1/enroll/
Obtendrás la siguiente respuesta:
HTTP/1.1 401 Unauthorized
...
{"detail": "Authentication credentials were not provided."}
Has obtenido un código HTTP 401 como se esperaba ya que no estás autenticado. Vamos a utilizar la autenticación básica con uno de tus usuarios. Ejecuta el siguiente comando, reemplazando student:password con las credenciales de un usuario existentey con la id de un curso que exista:
curl -i -X POST -u student:password http://127.0.0.1:8000/api/courses/1/enroll/
Obtendrás la siguiente respuesta:
HTTP/1.1 200 OK
...
{"enrolled": true}
Puedes acceder al sitio de administración y verificar que el usuario ahora está inscrito en el curso.
A continuación, aprenderás una forma diferente de construir vistas comunes utilizando ViewSets.
Creando ViewSets y Rutas.
Elearning/educa/courses/api/views.py
# ... from rest_framework import viewsets from courses.api.serializers import SubjectSerializer, CourseSerializer class CourseViewSet(viewsets.ReadOnlyModelViewSet): queryset = Course.objects.all() serializer_class = CourseSerializer
Las subclases ReadOnlyModelViewSet nos proporciona las acciones de solo lectura list() y retrieve() para listar objetos o recuperar un único objeto.
Edita el archivo api/urls.py y crea una ruta para nuestra ViewSet de la siguiente forma:
Elearning/educa/courses/api/urls.py
from django.urls import path, include from rest_framework import routers from . import views router = routers.DefaultRouter() router.register('courses', views.CourseViewSet) urlpatterns = [ # ... path('', include(router.urls)), ]
Creas un objeto DefaultRouter y registras tu ViewSet con el prefijo 'courses'. El enrutador se encarga de generar automáticamente las URLs para tu ViewSet.
Abre http://127.0.0.1:8000/api/ en tu navegador. Verás que el enrutador lista todos los ViewSets en su URL base, como se muestra en la siguiente imagen:
Puedes acceder a http://127.0.0.1:8000/api/courses/ para recuperar la lista de cursos. Puedes obtener más información sobre ViewSets en https://www.django-rest-framework.org/api-guide/viewsets/. También puedes encontrar más información sobre routers en https://www.django-rest-framework.org/api-guide/routers/.
Añadiendo acciones adicionales al ViewSet.
Puedes añadir acciones adicionales a los ViewSets. Vamos a cambiar tu vista anterior CourseEnrollView en una acción personalizada de ViewSet. Edita el archivo api/views.py y modifica la clase CourseViewSet de la siguiente manera:
Elearning/educa/courses/api/views.py
# ... from rest_framework.decorators import action class CourseViewSet(viewsets.ReadOnlyModelViewSet): queryset = Course.objects.all() serializer_class = CourseSerializer @action(detail=True, methods=['post'], authentication_classes=[BasicAuthentication], permission_classes=[IsAuthenticated]) def enroll(self, request, *args, **kwargs): course = self.get_object() course.students.add(request.user) return Response({'enrolled': True})
En el código anterior, añades un método enroll() personalizado que representa una acción adicional para este ViewSet. El código anterior es el siguiente:
1. Utilizas el decorador de acción del framework con el parámetro detail=True para especificar que esta es una acción que se realizará en un único objeto.
2. El decorador te permite añadir atributos personalizados para la acción. Especificas que solo se permite el método post() para esta vista y estableces las clases de autenticación y permisos.
3. Utilizas self.get_object() para recuperar el objeto Curso.
4. Añades el usuario actual a la relación muchos a muchos de estudiantes y devuelves una respuesta de éxito personalizada.
Edita el archivo api/urls.py y elimina o comenta la siguiente URL, ya que ya no la necesitaremos más:
Elearning/educa/courses/api/urls.py
path('courses/<pk>/enroll/', views.CourseEnrollView.as_view(), name='course_enroll'),
Luego, edita el archivo api/views.py y elimina o comenta la clase CourseEnrollView.
La URL para inscribirse en los cursos ahora se genera automáticamente por el enrutador. La URL sigue siendo la misma ya que se construye dinámicamente utilizando el nombre de la acción, enroll.
Después de que los estudiantes se inscriben en un curso, necesitan acceder al contenido del mismo. A continuación, aprenderás cómo asegurarte de que solo los estudiantes inscritos puedan acceder al curso.
Creando permisos personalizados.
Quieres que los estudiantes puedan acceder al contenido de los cursos en los que están inscritos. Solo los estudiantes inscritos en un curso deberían poder acceder a su contenido. La mejor manera de hacer esto es con una clase de permiso personalizada. Framework REST proporciona una clase BasePermission que te permite definir los siguientes métodos:
- has_permission(): Verificación de permisos a nivel de vista
- has_object_permission(): Verificación de permisos a nivel de instancia
Estos métodos deben devolver True para otorgar acceso, o False de lo contrario.
Crea un nuevo archivo dentro del directorio courses/api/ y llámalo permissions.py. Añade el siguiente código en él:
Elearning/educa/courses/api/permissions.py
from rest_framework.permissions import BasePermission class IsEnrolled(BasePermission): def has_object_permission(self, request, view, obj): return obj.students.filter(id=request.user.id).exists()
Subclasificas la clase BasePermission y sobrescribes el método has_object_permission(). Verificas que el usuario que realiza la solicitud esté presente en la relación students del objeto Curso. A continuación, vas a utilizar el permiso IsEnrolled.
Serializando el contenido del curso.
Necesitamos serializar el contenido del curso. El modelo Content incluye una clave foránea genérica que te permite asociar objetos de diferentes modelos de contenido. Sin embargo, agregamos un método render() común para todos los modelos de contenido. Puedes usar este método para proporcionar contenido renderizado a tu API.
Edita el archivo api/serializers.py de la aplicación de courses y añade el siguiente código:
Elearning/educa/courses/api/serializers.py
from courses.models import Subject, Course, Module, Content
class ItemRelatedField(serializers.RelatedField):
def to_representation(self, value):
return value.render()
class ContentSerializer(serializers.ModelSerializer):
item = ItemRelatedField(read_only=True)
class Meta:
model = Content
fields = ['order', 'item']
En este código, definimos un campo personalizado subclaseando el campo serializador RelatedField proporcionado por el framework REST y sobrescribiendo el método to_representation(). Definimos el serializador ContentSerializer para el modelo Content y utilizas el campo personalizado para el campo genérico de clave externa item.
Necesitamos un serializador alternativo para el modelo Module que incluya su contenido, así como también un Course serializer extendido. Edita el archivo api/serializers.py y añade el siguiente código:
Elearning/educa/courses/api/serializers.py
class ModuleWithContentsSerializer(serializers.ModelSerializer): contents = ContentSerializer(many=True) class Meta: model = Module fields = ['order', 'title', 'description', 'contents'] class CourseWithContentsSerializer(serializers.ModelSerializer): modules = ModuleWithContentsSerializer(many=True) class Meta: model = Course fields = ['id', 'subject', 'title', 'slug', 'overview', 'created', 'owner', 'modules']
Vamos a crear una vista que imite el comportamiento de la acción retrieve(), pero que incluya el contenido del curso. Edita el archivo api/views.py y añade el siguiente método a la clase CourseViewSet:
Elearning/educa/courses/api/views.py
from courses.api.permissions import IsEnrolled from courses.api.serializers import CourseWithContentsSerializer class CourseViewSet(viewsets.ReadOnlyModelViewSet): # ... @action(detail=True, methods=['get'], serializer_class=CourseWithContentsSerializer, authentication_classes=[BasicAuthentication], permission_classes=[IsAuthenticated, IsEnrolled]) def contents(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs)
La descripción de este método es la siguiente:
1. Utilizas el decorador de acción con el parámetro detail=True para especificar una acción que se realiza en un único objeto.
2. Especificas que solo se permite el método GET para esta acción.
3. Utilizas la nueva clase de serializador CourseWithContentsSerializer que incluye el contenido del curso renderizado.
4. Utilizas tanto IsAuthenticated como tus permisos personalizados IsEnrolled. Al hacerlo, te aseguras de que solo los usuarios inscritos en el curso puedan acceder a su contenido.
5. Utilizas la acción retrieve() existente para devolver el objeto Curso.
Abre http://127.0.0.1:8000/api/courses/2/contents/ en tu navegador. Si accedes a la vista con las credenciales correctas, verás que cada módulo del curso incluye el HTML renderizado para el contenido del curso.
Has construido una API simple que permite a otros servicios acceder a la aplicación de cursos de manera programática. REST framework también te permite manejar la creación y edición de objetos con la clase ModelViewSet.
Hemos cubierto los aspectos principales del framework Django REST, pero encontrarás más información sobre sus características en su extensa documentación en https://www.django-rest-framework.org/.
Utilizando la API RESTful
Ahora que hemos implementado una API, puedes utilizarla desde otras aplicaciones. Puedes interactuar con la API utilizando la Fetch API de JavaScript en el frontend de tu aplicación.
También puedes utilizar la API desde aplicaciones construidas con Python o cualquier otro lenguaje de programación. Crearemos una aplicación Python simple que utilice la API RESTful para recuperar todos los cursos disponibles y luego inscribir a un estudiante en todos ellos. Aprenderás cómo autenticarte contra la API utilizando autenticación básica de HTTP y realizar solicitudes GET y POST.
Para ello vamos a utilizar la biblioteca Python Requests. Requests abstrae la complejidad de tratar con solicitudes HTTP y proporciona una interfaz muy simple para consumir servicios HTTP. Puedes encontrar la documentación para la biblioteca Requests en https://requests.readthedocs.io/en/master/.
Abre el shell e instala la librería requests.
pip install requests
Crea un nuevo directorio al mismo nivel que el directorio educa y llámalo api_examples. Crea un nuevo archivo dentro de este nuevo directorio y llámalo enroll_all.py. La estructura del directorio debería ser parecida a esta:
enroll_all.py
educa/
....
Edita este nuevo archivo y añade el siguiente código:
Elearning/educa/api_examples/enroll_all.py
import requests
base_url = 'http://127.0.0.1:8000/api/'
# devuelve todos los cursos disponibles en la base de datos
r = requests.get(f'{base_url}courses/')
# trasforma el formato json en un diccionario python
courses = r.json()
available_courses = ', '.join([course['title'] for course in courses])
print(f'Available courses: {available_courses}')
Con este código realizamos las siguientes acciones.
- Importamos la librería requests y definimos la URL base de la API.
- Usamos requests.get() para obtener los datos de la API al enviar una petición get a la URL 'http:/127.0.0.1:8000/api/courses/. Esta dirección de la API se puede acceder de forma pública, así que no hace falta autenticación.
- Usamos el método json() para trasformar los datos en formato json proporcionados por la API a un diccionario Python.
- Imprimimos el atributo 'nombre' de cada curso.
$ python enroll_all.py
Available courses: Matemáticas Discretas., Curso 2, Curso 1
Elearning/educa/api_examples/enroll_all.py
import requests username = '' password = '' base_url = 'http://127.0.0.1:8000/api/' # devuelve todos los cursos disponibles en la base de datos r = requests.get(f'{base_url}courses/') # trasforma el formato json en un diccionario python courses = r.json() available_courses = ', '.join([course['title'] for course in courses]) print(f'Available courses: {available_courses}') for course in courses: course_id = course['id'] course_title = course['title'] r = requests.post(f'{base_url}courses/{course_id}/enroll/', auth=(username, password)) if r.status_code == 200: # successful request print(f'Successfully enrolled in {course_title}')
- Defines el usuario y contraseña del estudiante que quieres apuntar a tus cursos.
- Iteras sobre los cursos disponibles devueltos desde el API.
- Guardas el ID del curso en la variable course_id y el nombre del curso en la variable course_title.
- Usamos requests.post() para enviar una solicitud post a la URL http://127.0.0.1:8000/api/courses/[id]/enroll/ para cada curso. Esta URL se corresponde a la vista del API CourseEnrollView, la cual nos permite apuntar a los estudiantes a los cursos. Construimos la URL para cada curso usando la variable course_id. La vista CourseEnrollView requiere autentificación. Usa los permisos de IsAuthenticated y los de la clase BasicAuthentication. La librería Requests soporta autenticación básica, lista para usar. Usas el parámetro auth para pasar una tupla con el nombre de usuario y la contraseña para autenticar al usuario usando la autenticación básica HTTP.
- Si el código de estado de la petición es 200 OK, imprimimos un mensaje para indicar que el usuario ha sido registrado en el curso con éxito.
Ejecuta la siguiente instrucción en un terminal dentro del directorio api_examples.
El código fuente de este capítulo se puede encontrar en este enlace de Github.
No hay comentarios:
Publicar un comentario