Authentifizieren mit GraphQL
Du kannst dich mit einem personal access token, der GitHub App oder der OAuth app bei der GraphQL-API authentifizieren.
Authentifizieren mit einem personal access token
Um dich mit einem personal access token zu authentifizieren, befolge die Schritte unter Verwalten deiner persönlichen Zugriffstoken. Die von dir angeforderten Daten bestimmen, welche Bereiche du benötigst.
Wähle beispielsweise den Bereich „read:user“ aus, um Daten zu Benutzer*innen anzufordern. Wähle den Bereich „public_repo“ aus, um Daten zu öffentlichen Repositorys anzufordern.
Wenn dein Token nicht über die erforderlichen Bereiche für den Zugriff auf eine Ressource verfügt, gibt die API eine Fehlermeldung zurück, in der die Bereiche angegeben werden, die dein Token benötigt.
Authentifizieren mit einer GitHub App
Wenn du die API im Namen einer Organisation oder eines anderen Benutzers nutzen möchtest, empfiehlt GitHub, dass du eine GitHub App verwendest. Um die Aktivität deiner App zuzuordnen, kannst du deine App als eine App-Installation authentifizieren lassen. Um App-Aktivitäten einemeiner Benutzerin zuzuordnen, kannst du deine App im Namen eines Benutzers bzw. einer Benutzerin authentifizieren. In beiden Fällen generierst du ein Token, das du zur Authentifizierung bei der GraphQL-API verwenden kannst. Weitere Informationen findest du unter Registrieren einer GitHub-App und unter Informationen zur Authentifizierung mit einer GitHub-App.
Authentifizieren mit OAuth app
Um dich mit einem OAuth-Token in einer OAuth app zu authentifizieren, musst du deine OAuth app entweder mit einem Webanwendungs- oder Geräteflow autorisieren. Anschließend kannst du mit dem erhaltenen Zugriffstoken auf die API zugreifen. Weitere Informationen finden Sie unter Erstellen einer OAuth-App und unter Autorisieren von OAuth-Apps.
Der GraphQL-Endpunkt
Die REST-API verfügt über zahlreiche Endpunkte; die GraphQL-API verfügt über einen einzelnen Endpunkt:
http(s)://HOSTNAME/api/graphql
Der Endpunkt bleibt konstant, unabhängig davon, welchen Vorgang du ausführst.
Kommunizieren mit GraphQL
Da GraphQL-Vorgänge aus Multiline JSON bestehen, empfiehlt GitHub die Verwendung des Explorers, um GraphQL-Aufrufe vorzunehmen. Du kannst auch curl
oder eine andere Bibliothek mit HTTP-Unterstützung verwenden.
In REST bestimmen HTTP-Verben den ausgeführten Vorgang. In GraphQL stellst du einen JSON-codierten Textkörper bereit, unabhängig davon, ob du eine Abfrage oder eine Mutation ausführst; daher lautet das HTTP-Verb POST
. Die Ausnahme ist eine Introspektionsabfrage, die für den Endpunkt einfach GET
ist. Weitere Informationen zu GraphQL und REST findest du unter Migrieren von REST zu GraphQL.
Zur Abfrage von GraphQL mit einem curl
-Befehl sendest du eine POST
-Anforderung mit JSON-Nutzdaten. Die Nutzlast muss eine Zeichenfolge namens query
enthalten:
curl -H "Authorization: bearer TOKEN" -X POST -d " \
{ \
\"query\": \"query { viewer { login }}\" \
} \
" http(s)://HOSTNAME/api/graphql
Hinweis: Der Zeichenfolgenwert von "query"
muss für Neue-Zeile-Zeichen ein Escapezeichen verwenden, anderenfalls wird das Schema nicht ordnungsgemäß analysiert. Verwende für den POST
-Text äußere doppelte Anführungszeichen und innere doppelte Anführungszeichen mit Escapezeichen.
Informationen zu Abfrage- und Mutationsvorgängen
Die beiden Typen zulässiger Vorgänge in der GraphQL-API von GitHub sind Abfragen und Mutationen. Wenn GraphQL mit REST verglichen wird, funktionieren Abfragen wie GET
-Anforderungen, während Mutationen wie POST
/PATCH
/DELETE
funktionieren. Der Mutationsname bestimmt, welche Änderung ausgeführt wird.
Weitere Informationen zur Ratenbegrenzung findest du unter Ratenbegrenzungen und Knotengrenzwerte für die GraphQL-API.
Abfragen und Mutationen teilen ähnliche Formen, mit einigen wichtigen Unterschieden.
Informationen zu Abfragen
GraphQL-Abfragen geben nur die von dir angegebenen Daten zurück. Beim Erstellen einer Abfrage musst du Felder in Feldern (auch als geschachtelte Unterfelder bezeichnet) angeben, bis nur noch Skalare zurückgegeben werden.
Abfragen sind wie folgt strukturiert:
query { JSON-OBJECT-TO-RETURN }
Ein reales Beispiel findest du unter Beispielabfrage.
Informationen zu Mutationen
Zum Erstellen einer Mutation musst du drei Dinge angeben:
- Mutationsname. Die Art der Änderung, die du ausführen möchtest.
- Eingabeobjekt. Die Daten, die du an den Server senden möchtest, bestehen aus Eingabefeldern. Übergib es als Argument an den Mutationsnamen.
- Nutzlastobjekt. Die Daten, die du vom Server zurückgeben möchtest; sie bestehen aus Rückgabefeldern. Übergib sie als Körper des Mutationsnamens.
Mutationen sind wie folgt strukturiert:
mutation { MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) { MUTATION-NAME-PAYLOAD } }
Das Eingabeobjekt in diesem Beispiel lautet MutationNameInput
, und das Nutzlastobjekt ist MutationNamePayload
.
In der Mutationsreferenz sind die aufgeführten Eingabefelder das, was du als Eingabeobjekt übergibst. Die aufgeführten Rückgabefelder sind das, was du als Nutzlastobjekt übergibst.
Ein reales Beispiel findest du unter Beispielmutation.
Arbeiten mit Variablen
Variablen können Abfragen dynamischer und leistungsfähiger machen, und sie können die Komplexität beim Übergeben von Mutationseingabeobjekten verringern.
Hinweis: Wenn du den Explorer verwendest, musst du Variablen im separaten Abfragevariablenbereich eingeben. Schließe nicht das Wort variables
vor dem JSON-Objekt ein.
Nachfolgend findest du eine Beispielabfrage mit einer einzelnen Variable:
query($number_of_repos:Int!) {
viewer {
name
repositories(last: $number_of_repos) {
nodes {
name
}
}
}
}
variables {
"number_of_repos": 3
}
Es gibt drei Schritte zum Verwenden von Variablen:
-
Definiere die Variable außerhalb des Vorgangs in einem
variables
-Objekt:variables { "number_of_repos": 3 }
Das Objekt muss gültiger JSON-Code sein. In diesem Beispiel wird ein einfacher
Int
-Variablentyp dargestellt, aber es ist möglich, komplexere Variablentypen wie Eingabeobjekte zu definieren. Du kannst hier auch mehrere Variablen definieren. -
Übergib die Variable als Argument an den Vorgang:
query($number_of_repos:Int!){
Das Argument ist ein Schlüssel-Wert-Paar, wobei der Schlüssel der Name ist, der mit
$
beginnt (z. B.$number_of_repos
), und der Wert der Typ (z. B.Int
). Gib zusätzlich mit!
an, ob der Typ erforderlich ist. Wenn du mehrere Variablen definiert hast, füge sie hier als mehrere Argumente ein. -
Verwende die Variable innerhalb des Vorgangs:
repositories(last: $number_of_repos) {
In diesem Beispiel ersetzen wir die Variable für die Anzahl der Repositorys, die abgerufen werden sollen. Wir geben einen Typ in Schritt 2 an, da GraphQL strenge Typisierung erzwingt.
Dieser Prozess macht das Abfrageargument dynamisch. Wir können nun einfach den Wert im variables
-Objekt ändern und den Rest der Abfrage unverändert lassen.
Mithilfe von Variablen als Argumente kannst du Werte im variables
-Objekt dynamisch aktualisieren, ohne die Abfrage zu ändern.
Beispielabfrage
Gehe die folgende komplexere Abfrage durch, die diese Informationen in einen Kontext einbindet.
Mit ihr wird das Repository octocat/Hello-World
gesucht, und sie gibt die 20 zuletzt geschlossenen Issues und jeweils den Titel, die URL und die ersten 5 Bezeichnungen zurück:
query {
repository(owner:"octocat", name:"Hello-World") {
issues(last:20, states:CLOSED) {
edges {
node {
title
url
labels(first:5) {
edges {
node {
name
}
}
}
}
}
}
}
}
Sieh dir Zeile für Zeile an, wie sie zusammengesetzt ist:
-
query {
Dein Ziel ist es, Daten vom Server zu lesen und nicht zu ändern. Daher lautet der Stammvorgang
query
. (Wenn du keinen Vorgang angibst, istquery
auch die Standardeinstellung.) -
repository(owner:"octocat", name:"Hello-World") {
Zu Beginn der Abfrage soll das
repository
-Objekt gesucht werden. Die Schemavalidierung gibt an, dass dieses Objekt einen Besitzer (owner
) und einname
-Argument erfordert. -
issues(last:20, states:CLOSED) {
Damit alle Issues im Repository berücksichtigt werden, rufen wir das
issues
-Objekt auf. (Wir könnten ein einzelnesissue
in einemrepository
abfragen, aber das erfordert, dass wir die Nummer des Issues kennen, das wir zurückgeben möchten, und diese als Argument angeben.)Einige Details zum
issues
-Objekt:- Die Dokumentation gibt an, dass dieses Objekt den Typ
IssueConnection
aufweist. - Die Schemavalidierung gibt an, dass dieses Objekt eine letzte (
last
) oder erste (first
) Nummer der Ergebnisse als Argument erfordert. Daher geben wir20
an. - Die Dokumentation gibt auch an, dass dieses Objekt ein
states
-Argument akzeptiert, das eineIssueState
-Aufzählung ist, dieOPEN
- oderCLOSED
-Werte akzeptiert. Damit nur geschlossene Issues gesucht werden, erhält der Schlüsselstates
den WertCLOSED
.
- Die Dokumentation gibt an, dass dieses Objekt den Typ
-
edges {
Wir wissen, dass
issues
eine Verbindung ist, da es den TypIssueConnection
aufweist. Zum Abrufen von Daten zu einzelnen Issues müssen wir überedges
auf den Knoten zugreifen. -
node {
Hier wird der Knoten am Ende des Edges abgerufen. Die
IssueConnection
-Dokumentation gibt an, dass der Knoten am Ende desIssueConnection
-Typs einIssue
-Objekt ist. -
Nachdem nun bekannt ist, dass wir ein
Issue
-Objekt abrufen, können wir anhand der Dokumentation die Felder angeben, die zurückgegeben werden sollen:title url labels(first:5) { edges { node { name } } }
Hier geben wir die Felder
title
,url
undlabels
desIssue
-Objekts an.Das Feld
labels
besitzt den TypLabelConnection
. Dalabels
eine Verbindung ist, müssen wir wie beimissues
-Objekt über die Edges der Verbindung zu einem verbundenen Knoten gelangen, demlabel
-Objekt. Auf dem Knoten können wir dielabel
-Objektfelder angeben, die zurückgegeben werden sollen, in diesem Fallname
.
Du stellst möglicherweise fest, dass die Ausführung dieser Abfrage für das öffentliche Hello-World
Octocat-Repository nicht viele Bezeichnungen zurückgibt. Versuche, sie auf einem deiner eigenen Repositorys auszuführen, die Bezeichnungen verwenden. Dann wirst du wahrscheinlich einen Unterschied sehen.
Beispielmutation
Mutationen erfordern häufig Informationen, die du nur ermitteln kannst, indem du zuerst eine Abfrage ausführst. In diesem Beispiel werden zwei Vorgänge gezeigt:
- Eine Abfrage zum Abrufen einer Issue-ID.
- Eine Mutation, um dem Issue eine Emoji-Reaktion hinzuzufügen.
query FindIssueID {
repository(owner:"octocat", name:"Hello-World") {
issue(number:349) {
id
}
}
}
mutation AddReactionToIssue {
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
reaction {
content
}
subject {
id
}
}
}
Obwohl du eine Abfrage und eine Mutation in das gleiche Explorer-Fenster aufnehmen kannst, wenn du ihnen Namen gibst (in diesem Beispiel FindIssueID
und AddReactionToIssue
), werden die Vorgänge als separate Aufrufe des GraphQL-Endpunkts ausgeführt. Es ist nicht möglich, eine Abfrage gleichzeitig mit einer Mutation auszuführen.
Gehen wir das Beispiel durch. Die Aufgabe klingt einfach: Füge einem Issue eine Emoji-Reaktion hinzu.
Wie wissen wir also, das mit einer Abfrage begonnen werden soll? Wir wissen es noch nicht.
Da wir Daten auf dem Server ändern möchten (ein Emoji an ein Issue anfügen), durchsuchen wir zu Beginn das Schema nach einer hilfreichen Mutation. Die Referenzdokumentation gibt die addReaction
-Mutation mit dieser Beschreibung an: Adds a reaction to a subject.
Perfekt!
Die Dokumentation für die Mutation listet drei Eingabefelder auf:
clientMutationId
(String
)subjectId
(ID!
)content
(ReactionContent!
)
Mit !
wird angegeben, dass subjectId
und content
erforderliche Felder sind. Es ist verständlich, dass content
erforderlich ist: Wir möchten eine Reaktion hinzufügen und müssen daher angeben, welches Emoji verwendet werden soll.
Aber warum ist subjectId
erforderlich? Es liegt daran, dass nur mit subjectId
bestimmt werden kann, auf welches Issue in welchem Repository reagiert werden soll.
Aus diesem Grund beginnen wir dieses Beispiel mit einer Abfrage: um die ID
abzurufen.
Sehen wir uns nun die Abfrage Zeile für Zeile an:
-
query FindIssueID {
Hier führen wir eine Abfrage aus und nennen sie
FindIssueID
. Beachte, dass die Benennung einer Abfrage optional ist; hier erhält sie einen Namen, damit wir sie in das gleiche Explorer-Fenster wie die Mutation aufnehmen können. -
repository(owner:"octocat", name:"Hello-World") {
Wir geben das Repository an, fragen dazu das
repository
-Objekt ab und übergeben die Argumenteowner
undname
. -
issue(number:349) {
Wir geben das Issue an, auf das reagiert werden soll, fragen dazu das
issue
-Objekt ab und übergeben einnumber
-Argument. -
id
Dies ist der Ort, an dem wir die
id
vonhttps://github.com/octocat/Hello-World/issues/349
abrufen, um sie als diesubjectId
zu übergeben.
Wenn wir die Abfrage ausführen, erhalten wir die id
: MDU6SXNzdWUyMzEzOTE1NTE=
Hinweis: Die in der Abfrage zurückgegebene id
ist der Wert, den wir als subjectID
in der Mutation übergeben werden. Weder die Dokumentation noch die Schemaintrospektion geben diese Beziehung an; Du musst die Konzepte hinter den Namen verstehen, um dies zu ermitteln.
Mit der bekannten ID können wir mit der Mutation fortfahren:
-
mutation AddReactionToIssue {
Hier führen wir eine Mutation aus und nennen sie
AddReactionToIssue
. Wie bei Abfragen ist die Benennung einer Mutation optional; hier erhält sie einen Namen, damit wir sie in das gleiche Explorer-Fenster wie die Abfrage aufnehmen können. -
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
Sehen wir uns diese Zeile an:
addReaction
ist der Name der Mutation.input
ist der erforderliche Argumentschlüssel. Dies ist für eine Mutation immerinput
.{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}
ist der erforderliche Argumentwert. Dies ist für eine Mutation immer ein Eingabeobjekt (daher die geschweiften Klammern) aus Eingabefeldern (in diesem FallsubjectId
undcontent
).
Wie wissen wir, welcher Wert für den Inhalt verwendet werden soll? Die
addReaction
-Dokumentation gibt an, dass das Feldcontent
den TypReactionContent
aufweist, wobei es sich um eine Enumeration handelt, da nur bestimmte Emoji-Reaktionen bei GitHub-Issues unterstützt werden. Dies sind die zulässigen Werte für Reaktionen (einige Werte weichen von den entsprechenden Emojinamen ab):Inhalt Emoji +1
👍 -1
👎 laugh
😄 confused
😕 heart
❤️ hooray
🎉 rocket
🚀 eyes
👀 -
Der Rest des Aufrufs besteht aus dem Nutzlastobjekt. Hier geben wir die Daten an, die vom Server zurückgegeben werden sollen, nachdem die Mutation durchgeführt wurde. Diese Zeilen stammen aus der
addReaction
-Dokumentation und weisen drei mögliche Rückgabefelder auf:clientMutationId
(String
)reaction
(Reaction!
)subject
(Reactable!
)
In diesem Beispiel geben wir die beiden erforderlichen Felder (
reaction
undsubject
) zurück, die beide über erforderliche Unterfelder verfügen (content
bzw.id
).
Wenn wir die Mutation ausführen, ist dies die Reaktion:
{
"data": {
"addReaction": {
"reaction": {
"content": "HOORAY"
},
"subject": {
"id": "MDU6SXNzdWUyMTc5NTQ0OTc="
}
}
}
}
Das ist alles! Sieh dir die Reaktion auf das Issue an, indem du auf „🎉“ zeigst, um deinen Benutzernamen zu finden.
Ein letzter Hinweis: Wenn du mehrere Felder in einem Eingabeobjekt übergibst, kann die Syntax unübersichtlich werden. Das Verschieben der Felder in eine Variable kann helfen. So kannst du die ursprüngliche Mutation mithilfe einer Variablen neu schreiben:
mutation($myVar:AddReactionInput!) {
addReaction(input:$myVar) {
reaction {
content
}
subject {
id
}
}
}
variables {
"myVar": {
"subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
"content":"HOORAY"
}
}
Du kannst feststellen, dass der content
-Feldwert im vorherigen Beispiel (in dem er direkt in der Mutation verwendet wird) keine Anführungszeichen um HOORAY
enthält; er enthält jedoch Anführungszeichen, wenn er in der Variablen verwendet wird. Hierfür gibt es einen Grund:
- Wenn du
content
direkt in der Mutation verwendest, erwartet das Schema für den Wert den TypReactionContent
, der eine Enumeration ist, keine Zeichenfolge. Die Schemaüberprüfung löst einen Fehler aus, wenn du Anführungszeichen um den Enumerationswert hinzufügst, da Anführungszeichen für Zeichenfolgen reserviert sind. - Wenn du
content
in einer Variablen verwendest, muss der Abschnitt für die Variablen gültiger JSON-Code sein, und daher sind die Anführungszeichen erforderlich. Die Schemaüberprüfung interpretiert den TypReactionContent
richtig, wenn die Variable während der Ausführung an die Mutation übergeben wird.
Weitere Informationen zum Unterschied zwischen Enumerationen und Zeichenfolgen findest du in der offiziellen GraphQL-Spezifikation.
Weitere Informationsquellen
Beim Erstellen von GraphQL-Aufrufen hast du zahlreiche weitere Möglichkeiten. Weitere Informationen findest du beispielsweise unter den folgenden Themen: