.. _restful_api: .. index:: single: API single: REST single: Open-Api-Spezifikation single: Swagger single: Spectacular Eine Restful API für unsere App ********************************* Ein anderes Unternehmen will unsere Events importieren und auf seiner App darstellen. Die Daten sollen im ``JSON-Format`` von unserer Website zur Verfügung gestellt werden und stets den aktuellen Zustand abbilden. Dazu benötigen wir eine API. Das Django Modul ``Django Restframework`` ist ein ausgereiftes Paket zur Erstellung von Rest-APIs in Django, die sich zudem komfortabel und einfach in bestehende Projekte integerieren lässt. Dennoch ist sie mächtig genug, um alles, was an API-Technologie benötigt werden könnte, umzusetzen. .. admonition:: Was ist eine REST-API? Ein Rest-API ist eine Web-API, die den Beschränkungen der REST-Architektur unterliegt und Interaktionen mit Webservices ermöglicht. Die Architektur basiert auf 6 Prinzipien, die vom Entwickler flexibel umgesetzt werden können. Es gilt die - **Client-Server-Architektur** - die **Zustandslosigkeit**, es werden also keine Nachrichtenteile etwa in Sessions gespeichert - es ist ein **Caching** implementiert - die **Schnittstelle ist einheitlich** - die **Systeme sind mehrschichtig** aufgebaut und **Code kann on Demand** an den Nutzer gesendet werden, um zum Beispiel via JavaScript weiterverarbeitet zu werden Mehr zu REST auf Wikipedia: ``_ Einrichten der API ===================================== Alles, was die API für die Event-App betrifft legen wir in ein eigenes Verzeichnis ``event_manager/events/api``. Dort legen wir drei Dateien an: ``serializers.py``, ``urls.py`` und ``views.py`` .. code-block:: bash event_manager/events ├───api │ serializers.py │ urls.py │ views.py Serializer ---------------- In ``serializers.py`` werden wir die Serialisierer für die aus- und eingehgenden Daten definieren. Unter Serialisierung versteht man in diesem Kontext den Prozess, ausgehende Daten vorweg in ein **Austauschformat** wie ``Json`` oder ``XML`` und eingehende Daten aus einem Austauschformat in **Python Datentypen** zu formatieren. URLS ------------------ Unsere Api benötigt natürlich auch wieder URLs, die von außen ansprechbar sind. ``http://127.0.0.1:8000/api/events`` wäre zum Beispiel eine solche URL. Views -------------- Bei den Views handelt es sich um Controller-Klassen, die die Daten bereitstellen, die serialisiert werden sollen. Legen wir zuerst die Serializer an: Serializer ================ Wir öffnen die Datei ``event_manager/events/api/serializers.py`` und fügen dort folgenden Code hinzu: .. literalinclude:: ../../../src/events/api_serializers_1.py Views ================ Für die Views nutzen wir die Viewsets aus dem Django-Restframework. Dazu legen wir die Datei ``event_manager/events/api/views.py`` an: .. literalinclude:: ../../../src/events/api_views.py Routes ================ Zuletzt müssen wir noch die URLs festlegen. Wir legen an: ``event_manager/events/api/urls.py`` .. literalinclude:: ../../../src/events/api_urls.py und verdrahten sie mit dem Projekt. Wir öffnen ``event_manager/event_manager/urls.py`` und fügen ein: .. code-block:: python from events.api.urls import router urlpatterns = [ # andere URLs path("api-auth/", include("rest_framework.urls")), path('api/', include(router.urls)), ] Via Api-Auth können wir uns auch via API am System einloggen: * ``_ * ``_ Diese Möglichkeit ist allerdings meistens gar nicht gewünscht, da eine Authentifizierung an einer API hauptsächlich über sogenannte ``Tokens`` gelöst wird, und nicht über gewöhnliche Sessions, wie man das von Webanwendungen oft gewohnt ist. OpenAPI-Spezifikation ======================== Die OpenAPI-Spezifikation (OAS) definiert eine standardisierte, sprachunabhängige Schnittstelle zu RESTful-APIs, die es sowohl Menschen als auch Computern ermöglicht, entfernte APIs bequem zu testen. Im Idealfall, dh. wenn das OpenAPI-Schema der API richtig implementiert ist, kann ein User mit der API über diese Schnittstelle interagieren. Eine OpenAPI-Definition kann zur Dokumentationserstellung und Code-Geniererung verwendet werden, um die API darzustellen. Eine API-Spezifiktation wird in ``YAML`` oder ``JSON`` geschrieben. **Mehr zu OAS hier** ``_ Swagger =========== Swagger ist eine Reihe von Open-Source-Tools, die auf der OpenAPI-Spezifikation basieren und bei der Entwicklung, Erstellung, Dokumentation und Nutzung von REST-APIs unterstützen. Um auf Basis der ``OpenAPI-Spezifikation`` eine interaktive Dokumentation zu erstellen, können wir ``Swagger`` nutzen. Um aus den Api-Endpunkten, die wir mit dem ``Django Restframework`` erstellt hatten, automatisch ein OpenAPI-Schema zu generieren, nutzen wir eine Django-App namens ``drf-spectacular``. Dieses Tool sucht nach Api-Endpunkten und erstellt daraus, u.a. auch on-the-fly ein Open-Api-Scheme, welches dann von ``drf-spectacular-sidecar`` genutzten werden kann, um eine ``Swagger-UI`` zu erstellen. Eine Swagger-UI ist nichts anderes, als eine schöne, interaktive Oberfläche zum Testen der API. Ein ähnliches Tool ist ``Redoc``. Auch die Anwendung ``Postman`` kann OpenApi-Daten lesen und daraus eine Oberfläche zum Testen der API bereitstellen. Es soll nicht unerwähnt bleiben, dass man das OpenAPI-Schema auch selber erstellen kann, da es sich hier um nichts weiter als eine YAML-Datei handelt. **Mehr zu Swagger and OpenApi** * ``_ * ``_ Swagger installieren ====================== Wir legen in der ``requirements.in`` die beiden folgenden Pakete fest: .. code-block:: bash # andere Apps drf-spectacular drf-spectacular-sidecar und installieren sie: .. code-block:: bash (eventenv) pip-compile requirements.in (eventenv) pip-sync requirements.txt requirements-dev.txt Mehr zu drf-specatular bzw. Sidecar hier: * ``_ * ``_ * ``_ in den ``settings/base.py`` registrieren wir ``drf-spectacular`` als ``DEFAULT_SCHEMA_CLASS`` des Restframeworks: .. code-block:: python REST_FRAMEWORK = { "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", } diese Klasse kümmert sich um das automatische Generieren der OpenApi-Spezifikation für unsere API-Anwendung. sowie in den INSTALLED APPS ... .. code-block:: python INSTALLED_APPS = [ [..] "django.contrib.admindocs", "crispy_forms", "crispy_bootstrap5", "rest_framework", "rest_framework.authtoken", "drf_spectacular", 'drf_spectacular_sidecar', [..] ] Ebenfalls in den ``settings/base.py`` legen wir die ``SPECTACULAR_SETTINGS`` an, die uns die Möglichkeit gibt, die API-Beschreibung zu anzupassen. .. code-block:: python SPECTACULAR_SETTINGS = { 'TITLE': 'Event Manager API', 'DESCRIPTION': 'Django Event manager', 'VERSION': '1.0.0', 'SERVE_INCLUDE_SCHEMA': False, 'SWAGGER_UI_DIST': 'SIDECAR', 'SWAGGER_UI_FAVICON_HREF': 'SIDECAR', 'SERVE_AUTHENTICATION': ['rest_framework.authentication.SessionAuthentication'], 'SERVE_PERMISSIONS': ['rest_framework.permissions.IsAuthenticated'], # OTHER SETTINGS } Hier haben wir einen Title und eine Description angelegt sowie einige spezfische Api-Einstellungen gesetzt. .. csv-table:: Wichtige SPECTACULAR_SETTINGS :widths: 40, 40 ``TITLE``, die Überschrift der Oberfläche ``DESCRIPTION``, eine Kurzbeschreibung der API. Hier ist auch HTML erlaubt. ``VERSION``, die aktuelle Version der API. ``SWAGGER_UI_DIST``, die graph. Oberfläche für die API Zusätzlich geben wir noch per ``SERVE_AUTHENTICATION`` und ``SERVE_PERMISSIONS`` die Rechte an, die nötig sind, um die ``SWAGGER-UI`` aufzurufen. Um die Api-Dokumentation via Url erreichbar zu machen, tragen wir den Path in die ``event_manager/event_manager/urls.py`` ein: .. code-block:: python from drf_spectacular.views import SpectacularAPIView from drf_spectacular.views import SpectacularSwaggerView urlpatterns = [ # andere urls path( "schema/", SpectacularAPIView.as_view(api_version="v2"), name="schema", ), path( "docs/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui", ), ] Beim Aufruf von ``http://127.0.0.1:8000/docs/`` sollte die Api-Dokumentation zu sehen sein. Alle Api-Endpunkte können nun ausprobiert werden. Das Schema wird autogeneriert und über ``urlname="schema"`` erreichbar gemacht. Man könnte dieses Schema auch über ein anderes Programm wie ``Redoc`` oder ``Postman`` integrieren. Mehr dazu unter: ``_ So sollte das Ergebnis jetzt aussehen: .. image:: /images/swagger_ui.png manage.py Subkommando spectacular ------------------------------------ Via ``manage.py`` steht uns mit ``spectacular`` ein neues Subkommando zur Verfügung, um mit der Anwedung zu interagieren. Um uns zum Beispiel das aktuelle API-Schema im ``YAML-Format`` ausgeben zu lassen, nutzen wir diese Befehl: .. code-block:: bash python manage.py spectacular --format openapi Im Hilfemodus der App können wir noch weitere Möglichkeiten finden. Probiert es aus! .. code-block:: bash python manage.py spectacular --help