Saltar al contenido
🐍 Curso de Python
/

Módulo 5 · Lección 21 de 30

Documentar con OpenAPI

Setenta operaciones documentadas solas, ninguna con un error, y un campo que la documentación dice que es texto y devuelve una lista.

⏱ 15 min de lectura

La lección 1 dijo que sin documentación una API no se puede usar, y las diez primeras lecciones lo confirmaron: la mitad del trabajo de consumir una API es averiguar qué devuelve.

OpenAPI es el formato estándar para describir una API, y se puede generar solo desde el código. Lo que hay que entender es qué parte se genera bien y qué parte no, porque una documentación generada tiene un problema que la escrita a mano no tiene: nadie la revisa.

Qué es OpenAPI#

Un fichero, YAML o JSON, que describe la API entera: rutas, métodos, parámetros, cuerpos, respuestas y tipos. Como es un formato estándar, sirve para muchas cosas:

Documentación navegable con formularios para probar, que es lo más visible.

Generar clientes en cualquier lenguaje, sin escribirlos.

Validar, comprobando en las pruebas que la API cumple lo que dice.

Importarlo en herramientas como Postman o Insomnia.

Esa última es la que suele cerrar la discusión: quien vaya a consumir tu API va a pedir el fichero, y dárselo ahorra semanas de correos.

Generarlo#

DRF trae un generador y no es el que conviene usar: cubre poco y está poco mantenido. El estándar de hecho es drf-spectacular.

bash
pip install drf-spectacular
python
INSTALLED_APPS = [..., 'drf_spectacular']

REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

SPECTACULAR_SETTINGS = {
    'TITLE': 'API del catálogo',
    'DESCRIPTION': 'Libros, autores y editoriales.',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
}
python
from drf_spectacular.views import (
    SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView)

urlpatterns = [
    path('api/esquema/', SpectacularAPIView.as_view(), name='esquema'),
    path('api/docs/', SpectacularSwaggerView.as_view(url_name='esquema')),
    path('api/redoc/', SpectacularRedocView.as_view(url_name='esquema')),
]

Con eso hay dos documentaciones navegables: la primera con formularios para probar, la segunda más limpia para leer. Y el fichero se puede sacar por la línea de órdenes:

bash
python manage.py spectacular --file esquema.yaml
Salida en pantalla
Schema generation summary:
Warnings: 2 (1 unique)
Errors:   0

2237 líneas
versión OpenAPI: 3.0.3
rutas: 34
esquemas de datos: 16

Dos mil doscientas líneas de documentación de un proyecto donde nadie ha escrito documentación. Eso es lo que hace que merezca la pena.

Lo que deduce solo#

Mucho, y de calidad. Los parámetros de un recurso con los filtros de la lección 19:

Salida en pantalla
editorial         in=query  string
estado            in=query  string  * `borrador` - Borrador
                                    * `publicado` - Publicado
ordering          in=query  string  Qué campo usar para ordenar los resultados
precio_max        in=query  number
precio_min        in=query  number
publicado_desde   in=query  string
search            in=query  string  Un término de búsqueda

Los filtros, la búsqueda y la ordenación aparecen solos, con las opciones válidas de los campos con estados y con las descripciones en español. Eso es exactamente lo que la lección 19 echaba en falta: quien consuma la API ve qué parámetros existen, y una errata deja de ser un misterio.

También deduce los campos de cada serializador con sus tipos y restricciones, cuáles son de solo lectura, cuáles obligatorios, y los esquemas de autenticación.

Lo que hay que escribir a mano#

El generador no sabe por qué existe un punto de acceso ni cómo se usa. Eso se escribe:

python
@extend_schema(
    summary='Buscar libros por texto',
    description=(
        'Busca en el título, el ISBN y los nombres de los autores.\n\n'
        'Las palabras se exigen todas. Usa comillas para una frase exacta:\n'
        '`?search="cien años"`.\n\n'
        'La búsqueda no distingue mayúsculas pero **sí distingue tildes**.'
    ),
    examples=[
        OpenApiExample('Por autor', value={'search': 'Marías'}),
        OpenApiExample('Frase exacta', value={'search': '"cien años"'}),
    ],
)
@action(detail=False)
def buscar(self, peticion):
        ...

Y hay tres cosas que conviene documentar siempre porque el generador no las deduce y son las que más se preguntan:

Cómo autenticarse, con un ejemplo completo de la cabecera. La lección 17 vio que DRF usa Token y no Bearer, y eso hay que decirlo en letras grandes.

Los límites de uso, que son la lección 9 desde el otro lado: cuántas peticiones, en qué ventana, qué cabeceras informan y qué pasa al pasarse.

Cómo paginar, y en particular cuál de los tres estilos de la lección 20 usa cada recurso.