Der Autor hat Girls Who Code dazu ausgewählt, im Rahmen des Programms Write for DOnations eine Spende zu erhalten.
GraphQL ist ein API-Standard, der von Facebook als Alternative zu REST-APIs entwickelt wurde und im Open-Source-Modell bereitgestellt wird. Im Gegensatz zu REST-APIs verwendet GraphQL ein typisiertes System zur Definition seiner Datenstruktur, wobei alle Daten, die gesendet und empfangen werden, einem vordefinierten Schema entsprechen müssen. Außerdem macht die Sprache einen einzigen Endpunkt für die gesamte Kommunikation verfügbar (anstelle unterschiedlicher URLs für verschiedene Ressourcen) und löst das Overfetching-Problem dadurch, dass nur die Daten zurückgegeben werden, die der Client angefordert hat. Somit werden kleinere und präzisere Antworten generiert.
In diesem Tutorial erstellen Sie ein Backend für einen URL-Shortener – einen Dienst, der aus einer beliebigen URL eine kürzere, besser lesbare Version generiert. Außerdem erfahren Sie mehr über GraphQL-Konzepte wie Abfragen und Mutationen sowie Tools (wie die GraphiQL-Oberfläche). Vielleicht haben Sie solche Dienste zuvor bereits verwendet, wie z. B. bit.ly
.
Da GraphQL eine sprachunabhängige Technologie ist, wird sie auf verschiedene Sprachen und Frameworks aufgesetzt. Hier verwenden Sie die allgemeine Python-Programmiersprache, das Django-Web-Framework sowie die Graphene-Django-Bibliothek als GraphQL-Python-Implementierung mit spezifischen Integrationen für Django.
Um mit diesem Tutorial fortzufahren, muss auf Ihrem Entwicklungsrechner Python Version 3.5 oder höher installiert sein. Um Python zu installieren, folgen Sie unserem Tutorial Installieren und Einrichten einer lokalen Programmierumgebung für Python 3 für Ihr Betriebssystem. Stellen Sie sicher, dass Sie auch eine virtuelle Umgebung einrichten und starten; um den Vorgaben in diesem Tutorial zu folgen, können Sie Ihr Projektverzeichnis shorty
nennen.
Grundlegende Kenntnisse über Django sind erwünscht, aber nicht zwingend. Wenn Sie neugierig sind, können Sie dieser Django-Entwicklungsreihe folgen, die von der DigitalOcean-Community erstellt wurde.
In diesem Schritt installieren Sie alle erforderlichen Tools für die Anwendung und Einrichtung Ihres Django-Projekts.
Sobald Sie Ihr Projektverzeichnis erstellt und Ihre virtuelle Umgebung gestartet haben (wie in den Voraussetzungen beschrieben), installieren Sie die erforderlichen Pakete mit pip
, dem Python-Paketmanager. In diesem Tutorial werden Django Version 2.1.7 und Graphene-Django Version 2.2.0 oder höher installiert:
- pip install "django==2.1.7" "graphene-django>==2.2.0"
Sie haben nun alle Werkzeuge, die Sie zur Erledigung Ihrer Aufgaben benötigen. Als Nächstes erstellen Sie ein Django-Projekt mit dem Befehl django-admin
. Ein Projekt ist der standardmäßige Django-Baustein: ein Satz von Ordnern und Dateien mit allem, was für die Entwicklung einer Webanwendung erforderlich ist. In diesem Fall nennen Sie Ihr Projekt shorty
und erstellen es in Ihrem aktuellen Ordner, indem Sie am Ende .
angeben:
- django-admin startproject shorty .
Nach der Erstellung Ihres Projekts führen Sie die Django-Migrationen durch. Diese Dateien enthalten von Django generierten Python-Code und sind für die Änderung der Struktur der Anwendung entsprechend den Django-Modellen verantwortlich. Änderungen können beispielsweise die Erstellung einer Tabelle beinhalten. Standardmäßig verfügt Django über einen eigenen Satz von Migrationen, die für Subsysteme wie Django-Authentifizierung zuständig sind. Daher müssen Sie sie mit dem folgenden Befehl ausführen:
- python manage.py migrate
Dieser Befehl verwendet den Python-Interpreter, um ein Django-Skript namens manage.py
aufzurufen, das für die Verwaltung verschiedener Aspekte Ihres Projekts verantwortlich ist, wie das Erstellen von Anwendungen oder die Ausführung von Migrationen.
Sie erhalten einen Output, der dem Folgenden ähnelt:
OutputOperations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
Sobald die Datenbank von Django bereit ist, starten Sie ihren lokalen Entwicklungsserver:
- python manage.py runserver
Dies ergibt:
OutputPerforming system checks...
System check identified no issues (0 silenced).
March 18, 2020 - 15:46:15
Django version 2.1.7, using settings 'shorty.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Dieser Befehl übernimmt die Eingabeaufforderung in Ihrem Terminal und startet den Server.
Besuchen Sie die Seite http://127.0.0.1:8000
in Ihrem lokalen Browser. Sie sehen diese Seite:
Um den Server zu stoppen und zu Ihrem Terminal zurückzukehren, drücken Sie Strg+C
. Wann immer Sie auf den Browser zugreifen müssen, stellen Sie sicher, dass der vorhergehende Befehl ausgeführt wird.
Als Nächstes beenden Sie diesen Schritt, indem Sie im Projekt die Django-Graphene-Bibliothek aktivieren. Django nutzt das Konzept von Apps
, von Webanwendungen mit einer spezifischen Aufgabe. Ein Projekt besteht aus einer oder mehreren Apps. Öffnen Sie jetzt die Datei shorty/settings.py
in Ihrem bevorzugten Text-Editor. In diesem Tutorial wird vim
verwendet:
- vim shorty/settings.py
Die Datei settings.py
verwaltet alle Einstellungen in Ihrem Projekt. Suchen Sie darin nach dem Eintrag INSTALLED_APPS
und fügen Sie die Zeile 'graphene_django'
hinzu:
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'graphene_django',
]
...
Dadurch erfährt Django, dass Sie eine App namens graphene_django
verwenden werden, die Sie in Schritt 1 installiert haben.
Fügen Sie am unteren Ende der Datei die folgende Variable hinzu:
...
GRAPHENE = {
'SCHEMA': 'shorty.schema.schema',
}
Diese letzte Variable verweist auf Ihr zentrales Schema, das Sie später erstellen werden. In GraphQL enthält ein Schema alle Objekttypen, wie Ressourcen, Abfragen und Mutationen. Stellen Sie sich ein Schema als Dokumentation aller Daten und Funktionen vor, die in Ihrem System verfügbar sind.
Speichern und schließen Sie die Datei nach Vornahme der Änderungen.
Jetzt haben Sie das Django-Projekt konfiguriert. Im nächsten Schritt werden Sie eine Django-App und ihre Modelle erstellen.
Eine Django-Plattform besteht normalerweise aus einem Projekt und vielen Anwendungen oder Apps. Eine App beschreibt eine Reihe von Funktionen innerhalb eines Projekts und kann, falls gut gestaltet, in Django wiederverwendet werden.
In diesem Schritt erstellen Sie eine App namens shortener
, die für die tatsächliche URL-Verkürzung verantwortlich ist. Geben Sie für die Erstellung des Fundaments den folgenden Befehl in Ihr Terminal ein:
- python manage.py startapp shortener
Hier haben Sie den Parameter startapp app_name
verwendet, um manage.py
anzuweisen, eine App namens shortener
zu erstellen.
Um die App-Erstellung abzuschließen, öffnen Sie die Datei shorty/settings.py
.
- vim shorty/settings.py
Fügen Sie den Namen der App dem gleichen INSTALLED_APPS
-Eintrag hinzu, den Sie zuvor geändert haben:
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'graphene_django'
'shortener',
]
...
Speichern und schließen Sie die Datei.
Nachdem Sie Ihren shortener
zu shorty/settings.py
hinzugefügt haben, können Sie mit der Erstellung der Modelle für Ihr Projekt fortfahren. Modelle sind eine der Schlüsselfunktionen in Django. Sie werden verwendet, um eine Datenbank auf eine “Python-artige” Weise darzustellen, sodass Sie Daten mit Python-Code verwalten, abfragen und speichern können.
Bevor die Datei models.py
für Änderungen geöffnet wird, bietet Ihnen dieses Tutorial einen Überblick über die Änderungen, die Sie vornehmen werden.
Ihre Modelldatei (shortener/models.py
) wird nach dem Austausch des vorhandenen Codes den folgenden Inhalt umfassen:
from hashlib import md5
from django.db import models
Hier importieren Sie die erforderlichen Pakete, die von Ihrem Code benötigt werden. Sie fügen oben die Zeile from hashlib import md5
hinzu, um die Standardbibliothek von Python zu importieren, die zur Erstellung eines Hash der URL verwendet wird. Die Zeile from django.db import models
ist eine Django-Hilfe für das Erstellen von Modellen.
Warnung: Dieses Tutorial verweist auf Hash als das Ergebnis einer Funktion, die eine Eingabe nimmt und immer dieselbe Ausgabe zurückgibt. In diesem Tutorial wird für Demonstrationszwecke die MD5-Hash-Funktion verwendet.
Beachten Sie, dass MD5 Kollisionsprobleme aufweist und in der Produktion vermieden werden sollte.
Als Nächstes fügen Sie ein Modell namens URL
mit den folgenden Feldern hinzu:
full_url
: die URL, die verkürzt werden soll.url_hash
: ein kurzer Hashwert, der die vollständige URL repräsentiert.clicks
: gibt darüber Auskunft, wie oft auf die kurze URL zugegriffen wurde.created_at
: Datum und Uhrzeit der Erstellung der URL....
class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
Sie generieren den url_hash
, indem Sie den MD5-Hash-Algorithmus auf das Feld full_url
anwenden und nur die ersten 10 Zeichen nutzen, die bei der save()
-Methode des Modells zurückgegeben werden; diese wird jedes Mal ausgeführt, wenn Django einen Eintrag in der Datenbank speichert. Außerdem verfolgen URL-Shortener meist, wie oft auf einen Link geklickt wurde. Sie können dies erreichen, indem Sie die Methode clicked()
aufrufen, wenn die URL von einem Benutzer besucht wird.
Die genannten Operationen werden mit diesem Code in Ihrem URL
-Modell hinzugefügt:
...
def clicked(self):
self.clicks += 1
self.save()
def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]
return super().save(*args, **kwargs)
Nachdem Sie den Code überprüft haben, öffnen Sie jetzt die Datei shortener/models.py
:
- vim shortener/models.py
Ersetzen Sie den Code mit dem folgenden Inhalt:
from hashlib import md5
from django.db import models
class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
def clicked(self):
self.clicks += 1
self.save()
def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]
return super().save(*args, **kwargs)
Speichern und schließen Sie die Datei.
Um diese Änderungen in der Datenbank anzuwenden, müssen Sie die entsprechenden Migrationen erstellen, indem Sie den folgenden Befehl ausführen:
- python manage.py makemigrations
Damit erhalten Sie die folgende Ausgabe:
OutputMigrations for 'shortener':
shortener/migrations/0001_initial.py
- Create model URL
Dann führen Sie die Migrationen aus:
- python manage.py migrate
Sie sehen in Ihrem Terminal folgende Ausgabe:
OutputOperations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, shortener
Running migrations:
Applying shortener.0001_initial... OK
Nachdem Sie nun die Modelle eingerichtet haben, werden Sie im nächsten Schritt den GraphQL-Endpunkt und eine Abfrage erstellen.
Die REST-Architektur macht verschiedene Ressourcen in verschiedenen Endpunkten verfügbar, jeweils mit einer genau definierten Datenstruktur. Zum Beispiel können Sie unter /api/users
eine Benutzerliste abrufen und dabei immer dieselben Felder erwarten. GraphQL hingegen verfügt über einen einzigen Endpunkt für alle Interaktionen und verwendet Abfragen für den Zugriff auf Daten. Der größte und wichtigste Unterschied besteht darin, dass Sie eine Abfrage verwenden können, um alle Ihre Benutzer im Rahmen einer einzigen Anfrage abzurufen.
Erstellen Sie zunächst eine Abfrage, um alle URLs abzurufen. Sie benötigen mehrere Dinge:
urls
.Erstellen Sie eine neue Datei namens shortener/schema.py
:
- vim shortener/schema.py
Fügen Sie zunächst die import
-Anweisungen von Python hinzu:
import graphene
from graphene_django import DjangoObjectType
from .models import URL
Die erste Zeile sorgt für den Import der wichtigsten graphene
-Bibliothek, die die grundlegenden GraphQL-Typen enthält, z. B. List
. Der DjangoObjectType
ist ein Helfer, der Sie bei der Erstellung einer Schemadefinition aus einem beliebigen Django-Modell unterstützt,während die dritte Zeile dafür sorgt, dass Ihr zuvor erstelltes URL
-Modell importiert wird.
Danach erstellen Sie einen neuen GraphQL-Typ für das Modell URL
, indem Sie die folgenden Zeilen hinzufügen:
...
class URLType(DjangoObjectType):
class Meta:
model = URL
Fügen Sie schließlich folgende Zeilen hinzu, um einen Abfragetyp für das URL
-Modell zu erstellen:
...
class Query(graphene.ObjectType):
urls = graphene.List(URLType)
def resolve_urls(self, info, **kwargs):
return URL.objects.all()
Dieser Code erstellt eine Query
-Klasse mit einem Feld namens urls
, das eine Liste des zuvor definierten URLType
ist. Wenn Sie die Abfrage mit der Methode resolve_urls
auflösen, geben Sie alle in der Datenbank gespeicherten URLs zurück.
Die vollständige Datei shortener/schema.py
wird hier angezeigt:
import graphene
from graphene_django import DjangoObjectType
from .models import URL
class URLType(DjangoObjectType):
class Meta:
model = URL
class Query(graphene.ObjectType):
urls = graphene.List(URLType)
def resolve_urls(self, info, **kwargs):
return URL.objects.all()
Speichern und schließen Sie die Datei.
Alle Abfragen müssen jetzt dem Hauptschema hinzugefügt werden. Stellen Sie sich das Schema als Behälter für alle Ihre Ressourcen vor.
Erstellen Sie eine neue Datei im Pfad shorty/schema.py
und öffnen Sie sie mit Ihrem Editor:
- vim shorty/schema
Importieren Sie die folgenden Python-Pakete, indem Sie folgende Zeilen hinzufügen. Die erste Zeile enthält, wie bereits erwähnt, die grundlegenden GraphQL-Typen. Die zweite Zeile importiert die zuvor erstellte Schemadatei.
import graphene
import shortener.schema
Fügen Sie als Nächstes die Haupt-Query
-Klasse hinzu. Sie wird via Vererbung alle Abfragen und künftig erstellten Operationen enthalten:
...
class Query(shortener.schema.Query, graphene.ObjectType):
pass
Erstellen Sie schließlich die Variable schema
:
...
schema = graphene.Schema(query=Query)
Die SCHEMA
-Einstellung, die Sie in Schritt 2 definiert haben, verweist auf die Variable schema
, die Sie gerade erstellt haben.
Die vollständige Datei shorty/schema.py
wird hier angezeigt:
import graphene
import shortener.schema
class Query(shortener.schema.Query, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query)
Speichern und schließen Sie die Datei.
Aktivieren Sie als Nächstes den GraphQL-Endpunkt und die GraphiQL-Oberfläche, die eine grafische Weboberfläche ist, die der Interaktion mit dem GraphQL-System dient.
Öffnen Sie die Datei shorty/urls.py
:
- vim shorty/urls.py
Zu Lernzwecken löschen Sie die Dateiinhalte und speichern sie, damit Sie ganz neu anfangen können.
Die ersten Zeilen, die Sie hinzufügen, sind Python-Importanweisungen:
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
Die Funktion path
wird von Django verwendet, um eine aufrufbare URL für die GraphiQL-Oberfläche zu erstellen. Danach importieren Sie csrf_exempt
, was es Clients ermöglicht, Daten an den Server zu senden. Eine vollständige Erklärung finden Sie in der Graphene-Dokumentation. In der letzten Zeile haben Sie über GraphQLView
den tatsächlichen Code importiert, der für die Oberfläche verantwortlich ist.
Erstellen Sie als Nächstes eine Variable namens urlpatterns
.
...
urlpatterns = [
path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),
]
Diese wird den gesamten Code zusammenfügen, der erforderlich ist, um die GraphiQL-Oberfläche im Pfad graphql/
verfügbar zu machen:
Die vollständige Datei shortener/urls.py
wird hier angezeigt:
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
urlpatterns = [
path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),
]
Speichern und schließen Sie die Datei.
Führen Sie zurück im Terminal den Befehl python manage.py runserver
aus (wenn er nicht bereits ausgeführt wird):
- python manage.py runserver
Öffnen Sie Ihren Webbrowser unter der Adresse http://localhost:8000/graphql
. Ihnen wird der folgende Bildschirm angezeigt:
GraphiQL ist eine Oberfläche, in der Sie GraphQL-Anweisungen ausführen und die Ergebnisse anzeigen können. Eine Funktion ist der Abschnitt Docs
oben rechts. Da alles in GraphQL typisiert ist, erhalten Sie eine freie Dokumentation für alle Ihre Typen, Abfragen, Mutationen usw.
Nach Erkundung der Seite fügen Sie im Haupttextbereich Ihre erste Abfrage ein:
query {
urls {
id
fullUrl
urlHash
clicks
createdAt
}
}
Dieser Inhalt zeigt, wie eine GraphQL-Abfrage strukturiert ist: Erstens verwenden Sie das Schlüsselwort query
, um dem Server zu sagen, dass Sie nur einige Daten zurückgeben möchten. Als Nächstes verwenden Sie das Feld urls
, das in der Datei shortener/schema.py
in der Klasse Query
definiert ist. Daraus fordern Sie ausdrücklich an, dass alle im URL
-Modell definierten Felder mit Höckerschrift definiert werden, was die Standardeinstellung für GraphQL ist.
Klicken Sie nun oben links auf die Wiedergabepfeiltaste.
Sie erhalten folgende Antwort, in der steht, dass Sie immer noch keine URLs haben:
Output{
"data": {
"urls": []
}
}
Dies zeigt, dass GraphQL funktioniert. Drücken Sie in Ihrem Terminal Strg+C
, um Ihren Server anzuhalten.
In diesem Schritt haben Sie viel erreicht: Sie haben den GraphQL-Endpunkt erstellt, eine Abfrage ausgeführt, um alle URLs abzurufen, und die GraphQL-Oberfläche aktiviert. Jetzt erstellen Sie Mutationen, um die Datenbank zu ändern.
Die meisten Anwendungen bieten eine Möglichkeit, den Datenbankzustand zu ändern, indem sie Daten hinzufügen, aktualisieren oder löschen. In GraphQL werden diese Operationen Mutationen genannt. Sie sehen wie Abfragen aus, verwenden aber Argumente, um Daten an den Server zu senden.
Um Ihre erste Mutation zu erstellen, öffnen Sie shortener/schema.py
:
- vim shortener/schema.py
Am Ende der Datei fügen Sie zunächst eine neue Klasse namens CreateURL
hinzu:
...
class CreateURL(graphene.Mutation):
url = graphene.Field(URLType)
Diese Klasse erbt das Hilfsprogramm graphene.Mutation
, um über die Fähigkeiten einer GraphQL-Mutation zu verfügen. Außerdem verfügt sie über einen Eigenschaftsnamen url
, der den Inhalt definiert, der vom Server nach Fertigstellung der Mutation zurückgegeben wird. In diesem Fall ist es die Datenstruktur URLType
.
Fügen Sie als Nächstes in der bereits definierten Klasse eine Unterklasse namens Arguments
hinzu:
...
class Arguments:
full_url = graphene.String()
Damit wird definiert, welche Daten vom Server akzeptiert werden. Hier erwarten Sie einen Parameter namens full_url
mit einem String
-Inhalt:
Fügen Sie jetzt folgende Zeilen hinzu, um die mutate
-Methode zu erstellen:
...
def mutate(self, info, full_url):
url = URL(full_url=full_url)
url.save()
Diese mutate
-Methode erledigt viele Aufgaben, indem sie Daten vom Client empfängt und in der Datenbank speichert. Am Ende gibt sie die Klasse selbst zurück, die das neu erstellte Element enthält.
Erstellen Sie schließlich eine Klasse Mutation
, die alle Mutationen für Ihre App enthält, indem Sie folgende Zeilen hinzufügen:
...
class Mutation(graphene.ObjectType):
create_url = CreateURL.Field()
Bisher verfügen Sie nur über eine Mutation namens create_url
.
Die vollständige Datei shortener/schema.py
wird hier angezeigt:
import graphene
from graphene_django import DjangoObjectType
from .models import URL
class URLType(DjangoObjectType):
class Meta:
model = URL
class Query(graphene.ObjectType):
urls = graphene.List(URLType)
def resolve_urls(self, info, **kwargs):
return URL.objects.all()
class CreateURL(graphene.Mutation):
url = graphene.Field(URLType)
class Arguments:
full_url = graphene.String()
def mutate(self, info, full_url):
url = URL(full_url=full_url)
url.save()
return CreateURL(url=url)
class Mutation(graphene.ObjectType):
create_url = CreateURL.Field()
Schließen und speichern Sie die Datei.
Um das Hinzufügen der Mutation abzuschließen, ändern Sie die Datei shorty/schema.py
:
- vim shorty/schema.py
Ändern Sie die Datei, indem Sie den folgenden hervorgehobenen Code einfügen:
import graphene
import shortener.schema
class Query(shortener.schema.Query, graphene.ObjectType):
pass
class Mutation(shortener.schema.Mutation, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query, mutation=Mutation)
Speichern und schließen Sie die Datei. Wenn Sie den lokalen Server noch nicht ausführen, starten Sie ihn:
- python manage.py runserver
Navigieren Sie in Ihrem Webbrowser zu http://localhost:8000/graphql
. Führen Sie Ihre erste Mutation in der GraphiQL-Weboberfläche aus, indem Sie folgende Anweisung ausführen:
mutation {
createUrl(fullUrl:"https://www.digitalocean.com/community") {
url {
id
fullUrl
urlHash
clicks
createdAt
}
}
}
Sie haben die Mutation mit dem Namen createURL
, das Argument fullUrl
und die Daten erstellt, die Sie in der im Feld url
definierten Antwort erhalten möchten.
Die Ausgabe enthält die URL-Informationen, die Sie gerade im GraphQL-Feld data
erstellt haben, wie hier gezeigt:
Output{
"data": {
"createUrl": {
"url": {
"id": "1",
"fullUrl": "https://www.digitalocean.com/community",
"urlHash": "077880af78",
"clicks": 0,
"createdAt": "2020-01-30T19:15:10.820062+00:00"
}
}
}
}
Damit wurde der Datenbank eine URL mit ihrer Hashversion hinzugefügt, wie Sie im Feld urlHash
sehen können. Versuchen Sie, die im letzten Schritt erstellte Abfrage auszuführen, um ihr Ergebnis zu sehen:
query {
urls {
id
fullUrl
urlHash
clicks
createdAt
}
}
Die Ausgabe zeigt die gespeicherte URL:
Output{
"data": {
"urls": [
{
"id": "1",
"fullUrl": "https://www.digitalocean.com/community",
"urlHash": "077880af78",
"clicks": 0,
"createdAt": "2020-03-18T21:03:24.664934+00:00"
}
]
}
}
Sie können auch versuchen, dieselbe Abfrage auszuführen, wobei Sie aber nur nach den gewünschten Feldern fragen.
Probieren Sie es als Nächstes noch einmal mit einer anderen URL:
mutation {
createUrl(fullUrl:"https://www.digitalocean.com/write-for-donations/") {
url {
id
fullUrl
urlHash
clicks
createdAt
}
}
}
Der Output sieht wie folgt aus:
Output{
"data": {
"createUrl": {
"url": {
"id": "2",
"fullUrl": "https://www.digitalocean.com/write-for-donations/",
"urlHash": "703562669b",
"clicks": 0,
"createdAt": "2020-01-30T19:31:10.820062+00:00"
}
}
}
}
Das System ist jetzt in der Lage, Kurz-URLs zu erstellen und aufzulisten. Im nächsten Schritt aktivieren Sie Benutzer, um eine URL anhand ihrer Kurzversion aufzurufen und die Benutzer auf die korrekte Seite weiterzuleiten.
In diesem Schritt verwenden Sie Django Views – eine Methode, die eine Anfrage übernimmt und eine Antwort zurückgibt –, um alle Benutzer, die auf den Endpunkt http://localhost:8000/url_hash
zugreifen, zur vollständigen URL umzuleiten.
Öffnen Sie die Datei shortener/views.py
mit Ihrem Editor:
- vim shortener/views.py
Importieren Sie zunächst zwei Pakete, indem Sie den Inhalt durch die folgenden Zeilen ersetzen:
from django.shortcuts import get_object_or_404, redirect
from .models import URL
Diese werden später noch genauer erläutert.
Als Nächstes erstellen Sie eine Django-Ansicht namens root
. Fügen Sie am Ende Ihrer Datei den für die Ansicht verantwortlichen Codeausschnitt hinzu:
...
def root(request, url_hash):
url = get_object_or_404(URL, url_hash=url_hash)
url.clicked()
return redirect(url.full_url)
Dadurch wird ein Argument namens url_hash
von der URL empfangen, die von einem Benutzer angefordert wurde. Innerhalb der Funktion versucht die erste Zeile, mit dem Argument url_hash
die URL aus der Datenbank abzurufen. Wenn die URL nicht gefunden wird, gibt sie den Fehler HTTP 404 an den Client zurück, was bedeutet, dass die Ressource fehlt. Anschließend wird die Eigenschaft clicked
des URL-Eintrags inkrementiert, sodass verfolgt wird, wie oft auf die URL zugegriffen wird. Am Ende leitet sie den Client zur angeforderten URL weiter.
Die vollständige Datei shortener/views.py
wird hier angezeigt:
from django.shortcuts import get_object_or_404, redirect
from .models import URL
def root(request, url_hash):
url = get_object_or_404(URL, url_hash=url_hash)
url.clicked()
return redirect(url.full_url)
Speichern und schließen Sie die Datei.
Öffnen Sie als Nächstes shorty/urls.py
:
- vim shorty/urls.py
Fügen Sie den folgenden hervorgehobenen Code hinzu, um die root
-Ansicht zu aktivieren.
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
from shortener.views import root
urlpatterns = [
path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),
path('<str:url_hash>/', root, name='root'),
]
Die root
-Ansicht wird im Pfad /
Ihres Servers zugänglich sein und akzeptiert einen url_hash
als Zeichenfolgenparameter.
Speichern und schließen Sie die Datei. Wenn Sie den lokalen Server nicht ausführen, starten Sie ihn durch Ausführung des Befehls python manage.py runserver
.
Um Ihre neue Hinzufügung zu testen, öffnen Sie Ihren Webbrowser und rufen Sie die URL http://localhost:8000/077880af78
auf. Beachten Sie, dass der letzte Teil der URL der Hash ist, der von der Mutation in Schritt 5 erstellt wurde. Sie werden zur URL-Seite des Hash, in diesem Fall die Website der DigitalOcean-Community, umgeleitet.
Nachdem nun die URL-Umleitung funktioniert, machen Sie die Anwendung sicherer, indem Sie bei Ausführung der Mutation eine Fehlerbehandlung implementieren.
Die Behandlung von Fehlern ist bei allen Anwendungen eine bewährte Methode, da Entwickler normalerweise nicht kontrollieren, was an den Server gesendet wird. Auf diese Weise können Sie versuchen, Fehler vorauszusehen und ihre Auswirkungen zu minimieren. In einem komplexen System wie GraphQL könnten viele Dinge schiefgehen: von Clients, die die falschen Daten anfragen, bis hin zum Server, der den Zugriff auf die Datenbank verliert.
Als typisiertes System kann GraphQL mit einer Operation namens Schemaüberprüfung alles überprüfen, was ein Client anfragt und empfängt. Sie können dies testen, indem Sie eine Abfrage mit einem nicht vorhandenen Feld erstellen.
Navigieren Sie in Ihrem Browser erneut zu http://localhost:8000/graphql
und führen Sie die nächste Abfrage innerhalb der GraphiQL-Oberfläche mit dem Feld iDontExist
aus:
query {
urls {
id
fullUrl
urlHash
clicks
createdAt
iDontExist
}
}
Da in Ihrer Abfrage kein iDontExist
-Feld vorhanden ist, gibt GraphQL eine Fehlermeldung zurück:
Output
{
"errors": [
{
"message": "Cannot query field \"iDontExist\" on type \"URLType\".",
"locations": [
{
"line": 8,
"column": 5
}
]
}
]
}
Dies ist wichtig, da im typisierten GraphQL-System das Ziel darin besteht, nur die Daten zu senden und zu empfangen, die bereits im Schema definiert sind.
Die aktuelle Anwendung akzeptiert jede beliebige Zeichenfolge im Feld full_url
. Das Problem besteht darin, dass Sie, wenn jemand eine schlecht konstruierte URL versendet, den Benutzer beim Versuch, die gespeicherten Daten abzurufen, ins Nirgendwo umleiten. In diesem Fall müssen Sie überprüfen, ob die full_url
richtig formatiert ist, bevor sie in der Datenbank gespeichert wird; falls es Fehler gibt, lösen Sie die Ausnahme GraphQLError
mit einer benutzerdefinierten Nachricht aus.
Lassen Sie uns diese Funktion in zwei Schritten implementieren. Öffnen Sie zunächst die Datei shortener/models.py
:
- vim shortener/models.py
Fügen Sie die hervorgehobenen Zeilen im import-Abschnitt hinzu:
from hashlib import md5
from django.db import models
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
from graphql import GraphQLError
...
Der URLValidator
ist ein Django-Hilfsprogramm zur Überprüfung einer URL-Zeichenfolge, während GraphQLError
von Graphene dazu verwendet wird, um Ausnahmen mit einer benutzerdefinierten Nachricht auszulösen.
Überprüfen Sie als Nächstes die vom Benutzer empfangene URL, bevor Sie sie in der Datenbank speichern. Aktivieren Sie diese Operation, indem Sie in der Datei shortener/models.py
den hervorgehobenen Code hinzufügen:
class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
def clicked(self):
self.clicks += 1
self.save()
def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]
validate = URLValidator()
try:
validate(self.full_url)
except ValidationError as e:
raise GraphQLError('invalid url')
return super().save(*args, **kwargs)
Zunächst instanziiert dieser Code den URLValidator
in der Variable validate
. Innerhalb des Blocks try/except
überprüfen Sie mit validate()
die empfangene URL und lösen einen GraphQLError
mit der benutzerdefinierten Nachricht Ungültige URL
aus, wenn etwas schiefgegangen ist.
Die vollständige Datei shortener/models.py
wird hier angezeigt:
from hashlib import md5
from django.db import models
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
from graphql import GraphQLError
class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
def clicked(self):
self.clicks += 1
self.save()
def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]
validate = URLValidator()
try:
validate(self.full_url)
except ValidationError as e:
raise GraphQLError('invalid url')
return super().save(*args, **kwargs)
Speichern und schließen Sie die Datei. Wenn Sie den lokalen Server noch nicht ausführen, starten Sie ihn mit dem Befehl python manage.py runserver
.
Testen Sie als Nächstes Ihre neue Fehlerbehandlung unter http://localhost:8000/graphql
. Versuchen Sie, in der GraphiQL-Oberfläche eine neue URL mit einer ungültigen full_url
zu erstellen:
mutation {
createUrl(fullUrl:"not_valid_url"){
url {
id
fullUrl
urlHash
clicks
createdAt
}
}
}
Wenn Sie eine ungültige URL senden, wird Ihre Ausnahme mit der benutzerdefinierten Nachricht ausgelöst:
Output
{
"errors": [
{
"message": "invalid url",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createUrl"
]
}
],
"data": {
"createUrl": null
}
}
Wenn Sie in Ihrem Terminal nachsehen, wo der Befehl python manage.py runserver
ausgeführt wird, wird ein Fehler angezeigt:
Output
...
graphql.error.located_error.GraphQLLocatedError: invalid url
[30/Jan/2020 19:46:32] "POST /graphql/ HTTP/1.1" 200 121
Ein GraphQL-Endpunkt wird immer mit einem HTTP 200-Statuscode fehlschlagen, was in der Regel Erfolg bedeutet. Denken Sie daran, dass GraphQL zwar auf HTTP aufbaut, jedoch nicht die Konzepte von HTTP-Statuscodes oder HTTP-Methoden verwendet, wie REST es tut.
Mit implementierter Fehlerbehandlung können Sie nun ein Verfahren zum Filtern Ihrer Abfrage einrichten, um die Daten zu minimieren, die vom Server zurückgegeben werden.
Stellen Sie sich vor, Sie haben den URL-Shortener genutzt, um eigene Links hinzuzufügen. Nach einer Weile gibt es so viele Einträge, dass es schwierig wird, die richtigen zu finden. Sie können dieses Problem durch Einsatz von Filtern lösen.
Filtern ist ein gängiges Konzept in REST-APIs, bei dem in der Regel ein Abfrageparameter mit einem Feld und Wert an die URL angehängt wird. Zum Beispiel können Sie zum Filtern aller Benutzer namens jojo GET /api/users?name=jojo
verwenden.
In GraphQL verwenden Sie Abfrageparameter als Filter. Sie sorgen für eine schöne und saubere Oberfläche.
Sie können das Problem des Auffindens einer URL lösen, indem Sie es dem Client mithilfe des Felds full_url
ermöglichen, URLs anhand von Namen zu filtern. Öffnen Sie dazu die Datei shortener/schema.py
in Ihrem bevorzugten Editor.
- vim shortener/schema.py
Importieren Sie zunächst die Methode Q
in die hervorgehobene Zeile:
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q
from .models import URL
...
Dies dient zum Filtern Ihrer Datenbankanfrage.
Als Nächstes schreiben Sie die gesamte Query
-Klasse mit dem folgenden Inhalt neu:
...
class Query(graphene.ObjectType):
urls = graphene.List(URLType, url=graphene.String())
def resolve_urls(self, info, url=None, **kwargs):
queryset = URL.objects.all()
if url:
_filter = Q(full_url__icontains=url)
queryset = queryset.filter(_filter)
return queryset
...
Die von Ihnen vorgenommenen Änderungen lauten:
url
innerhalb der Variable urls
und der Methode resolve_url
.resolve_urls
ein Parameter namens url
angegeben wird, werden beim Filtern der Datenbank mit der Methode Q(full_url__icontains=url)
nur URLs zurückgegeben, die den angegebenen Wert enthalten.Die vollständige Datei shortener/schema.py
wird hier angezeigt:
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q
from .models import URL
class URLType(DjangoObjectType):
class Meta:
model = URL
class Query(graphene.ObjectType):
urls = graphene.List(URLType, url=graphene.String())
def resolve_urls(self, info, url=None, **kwargs):
queryset = URL.objects.all()
if url:
_filter = Q(full_url__icontains=url)
queryset = queryset.filter(_filter)
return queryset
class CreateURL(graphene.Mutation):
url = graphene.Field(URLType)
class Arguments:
full_url = graphene.String()
def mutate(self, info, full_url)
url = URL(full_url=full_url)
url.save()
return CreateURL(url=url)
class Mutation(graphene.ObjectType):
create_url = CreateURL.Field()
Speichern und schließen Sie die Datei. Wenn Sie den lokalen Server noch nicht ausführen, starten Sie ihn mit dem Befehl python manage.py runserver
.
Testen Sie Ihre letzten Änderungen unter http://localhost:8000/graphql
. Schreiben Sie in der GraphiQL-Oberfläche die folgende Anweisung. Dadurch werden alle URLs mit dem Wort community gefiltert:
query {
urls(url:"community") {
id
fullUrl
urlHash
clicks
createdAt
}
}
Die Ausgabe umfasst nur einen Eintrag, da Sie nur eine URL mit der Zeichenfolge community
hinzugefügt haben. Wenn Sie zuvor weitere URLs hinzugefügt haben, kann Ihre Ausgabe anders aussehen.
Output
{
"data": {
"urls": [
{
"id": "1",
"fullUrl": "https://www.digitalocean.com/community",
"urlHash": "077880af78",
"clicks": 1,
"createdAt": "2020-01-30T19:27:36.243900+00:00"
}
]
}
}
Nun haben Sie die Möglichkeit, Ihre URLs zu durchsuchen. Bei zu vielen Links beschweren sich Ihre Clients ggf. jedoch, dass die URL-Liste mehr Daten zurückgibt, als ihre Apps bewältigen können. Um dieses Problem zu lösen, werden Sie Paginierung implementieren.
Clients, die Ihr Backend verwenden, beschweren sich möglicherweise darüber, dass die Antwortzeit zu lange oder die Größe übermäßig ist, falls es zu viele URL-Einträge gibt. Außerdem kann Ihre Datenbank Probleme damit bekommen, eine riesige Menge von Daten zusammenzustellen. Um dieses Problem zu lösen, können Sie es dem Client anhand eines Verfahrens namens Paginierung gestatten festzulegen, wie viele Elemente innerhalb einer Anfrage zurückgegeben werden.
Es gibt keine Standardmethode zur Implementierung dieser Funktion. Auch in REST-APIs sehen Sie sie ggf. in HTTP-Headern oder Abfrageparametern – mit verschiedenen Namen und Verhaltensweisen.
In dieser Anwendung werden Sie Paginierung implementieren, indem Sie zunächst zwei weitere Argumente für die URL-Abfrage aktivieren: first
und skip
. first
wählt die erste Variablenzahl von Elementen aus, während skip
angibt, wie viele Elemente vom Anfang aus übersprungen werden sollen. Wenn Sie zum Beispiel first == 10
und skip == 5
verwenden, werden die ersten 10 URLs abgerufen, jedoch 5 von ihnen übersprungen, sodass nur die verbleibenden 5 zurückgegeben werden.
Die Implementierung dieser Lösung ähnelt dem Hinzufügen eines Filters.
Öffnen Sie die Datei shortener/schema.py
:
- vim shortener/schema.py
Ändern Sie in der Datei die Query
-Klasse, indem Sie die beiden neuen Parameter in der Variable urls
und der Methode resolve_urls
hinzufügen, wie im folgenden Code hervorgehoben:
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q
from .models import URL
class Query(graphene.ObjectType):
urls = graphene.List(URLType, url=graphene.String(), first=graphene.Int(), skip=graphene.Int())
def resolve_urls(self, info, url=None, first=None, skip=None, **kwargs):
queryset = URL.objects.all()
if url:
_filter = Q(full_url__icontains=url)
queryset = queryset.filter(_filter)
if first:
queryset = queryset[:first]
if skip:
queryset = queryset[skip:]
return queryset
...
Dieser Code verwendet die neu erstellten Parameter first
und skip
innerhalb der Methode resolve_urls
zum Filtern der Datenbankabfrage.
Speichern und schließen Sie die Datei. Wenn Sie den lokalen Server noch nicht ausführen, starten Sie ihn mit dem Befehl python manage.py runserver
.
Um die Paginierung zu testen, geben Sie in der GraphiQL-Oberfläche unter http://localhost:8000/graphql
folgende Abfrage ein:
query {
urls(first: 2, skip: 1) {
id
fullUrl
urlHash
clicks
createdAt
}
}
Ihr URL-Shortener gibt die zweite in Ihrer Datenbank erstellte URL zurück:
Output
{
"data": {
"urls": [
{
"id": "2",
"fullUrl": "https://www.digitalocean.com/write-for-donations/",
"urlHash": "703562669b",
"clicks": 0,
"createdAt": "2020-01-30T19:31:10.820062+00:00"
}
]
}
}
Das bedeutet, dass die Paginierung funktioniert. Probieren Sie die Funktion aus, indem Sie weitere URLs hinzufügen und verschiedene Sätze von first
und skip
testen.
Das gesamte GraphQL-Ökosystem wächst von Tag zu Tag und beruht auf einer aktiven Community. Bei Firmen wie GitHub und Facebook hat sich bereits gezeigt, dass es bereit für die Produktion ist; jetzt können Sie diese Technologie also für Ihre eigenen Projekte verwenden.
In diesem Tutorial haben Sie mit GraphQL, Python und Django unter Verwendung von Konzepten wie Abfragen und Mutationen einen URL-Shortener erstellt. Darüber hinaus wissen Sie jetzt, wie Sie diese Technologien nutzen können, um mit dem Django-Web-Framework Webanwendungen zu erstellen.
Weitere Informationen über GraphQL und die hier verwendeten Tools finden Sie auf der GraphQL-Website sowie der Website mit der Graphene-Dokumentation. Außerdem verfügt DigitalOcean über zusätzliche Tutorials für Python und Django, die Sie verwenden können, falls Sie mehr über diese beiden Lösungen erfahren möchten.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!