Проверка подлинности с помощью GraphQL
Вы можете аутентифицироваться в API GraphQL с помощью personal access token, GitHub App, или OAuth app.
Аутентификация с помощью personal access token
Для аутентификации personal access tokenс помощью , следуйте шагам в Управление личными маркерами доступа. Запрашиваемые данные определяют, какие области или разрешения потребуются.
Например, выберите разрешение "issues:read", чтобы прочитать все проблемы в репозиториях, к которым ваш токен имеет access.
Все fine-grained personal access tokens имеют доступ к публичным репозиториям. Чтобы получить доступ к публичным репозиториям с personal access token (classic)помощью , выберите область действия "public_repo".
Если у вашего токена нет необходимых областей объёмов или разрешений для access к ресурсу, API выдаст сообщение об ошибке с указанием области или разрешений, которые нужны вашему токену.
Аутентификация с помощью GitHub App
Если вы хотите использовать API от имени организации или другого пользователя, GitHub рекомендуется использовать GitHub App. Чтобы атрибутировать действие для приложения, можно выполнить проверку подлинности приложения в качестве установки приложения. Чтобы атрибутировать действие приложения пользователю, можно выполнить проверку подлинности приложения от имени пользователя. В обоих случаях вы создайте маркер, который можно использовать для проверки подлинности в API GraphQL. Для получения дополнительной информации см. Регистрация приложения GitHub и Об аутентификации с помощью приложения GitHub.
Аутентификация с помощью OAuth app
Для аутентификации с помощью токена OAuth OAuth appиз , сначала необходимо авторизировать OAuth app использование веб-приложения или device flow. Затем вы можете использовать полученный токен access для access к API. Для получения дополнительной информации см. Создание приложения OAuth и Авторизация приложений OAuth.
Конечная точка GraphQL
REST API имеет множество конечных точек. С ПОМОЩЬЮ API GraphQL конечная точка остается постоянной, независимо от того, какая операция выполняется. Для GitHub.comGitHub Enterprise Server, эта конечная точка выглядит:
https://api.github.com/graphql
Если вы получаете доступ GitHub в другом домене, например octocorp.ghe.com, конечная точка будет отражать этот домен. Например: https://api.octocorp.ghe.com/graphql.
Взаимодействие с GraphQL
Поскольку операции GraphQL состоят из многолинейного JSON, GitHub рекомендуется использовать GraphQL Clients для выполнения вызовов GraphQL. Вы также можете использовать curl или любую другую библиотеку HTTP-речи.
В REST HTTP-команды определяют выполняемую операцию. В GraphQL вы предоставите текст в кодировке JSON независимо от того, выполняете ли вы запрос или изменение, поэтому HTTP-команда — POST. Исключение — запрос интроспекционный, который представляет собой простой GET к конечной точке. Для получения дополнительной информации о GraphQL и REST см. Миграция из REST в GraphQL.
Чтобы запросить GraphQL в команде curl , выполните POST запрос с полезными данными JSON. Полезные данные должны содержать строку query:
curl -H "Authorization: bearer TOKEN" -X POST -d " \
{ \
\"query\": \"query { viewer { login }}\" \
} \
" https://api.github.com/graphql
Примечание.
Строковое значение "query" должно экранировать символы новой строки или схема не будет правильно анализировать ее. Для текста запроса POST используйте внешние двойные кавычки и экранированные внутренние двойные кавычки.
Операции запроса и изменения
Два типа разрешённых операций в API GraphQL GitHub — это запросы и мутации. Если сравнивать GraphQL с REST, запросы работают как запросы GET, а изменения — как POST/PATCH/DELETE. Имя мутации определяет, какая модификация будет выполнена.
Сведения об ограничении скорости см. в разделе Ограничения скорости и ограничения запросов для API GraphQL.
Запросы и изменения похожи по форме за несколькими важными различиями.
Сведения о запросах
Запросы GraphQL возвращают только указанные данные. Чтобы сформировать запрос, необходимо указать поля внутри полей (также известных как вложенные подполя), пока не вернёте только скаляры.
Запросы имеют следующую структуру:
query {
JSON-OBJECT-TO-RETURN
}
Пример реального мира см. в разделе "Пример запроса".
Сведения об изменениях
Чтобы сформировать изменение, необходимо указать три элемента.
- Имя изменения — тип нужного изменения.
- Входной объект — данные, которые необходимо отправить на сервер; состоят из полей входных данных. Передайте его в качестве аргумента имени изменения.
- Объект полезных данных — данные, которые должны быть получены с сервера; состоят из возвращаемых полей. Передайте его в качестве тела имени мутации.
Изменения имеют следующую структуру:
mutation {
MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) {
MUTATION-NAME-PAYLOAD
}
}
Входной объект в этом примере — MutationNameInput, а объект полезных данных — MutationNamePayload.
В ссылке на mutations указаны поля входа — это то, что вы передаёте как объект входа. Кроме того, перечислены возвращаемые поля, передаваемые в качестве объекта полезных данных.
Пример изменения в реальном мире см. в разделе "Пример изменения".
Работа с переменными
Переменные могут сделать запросы более динамичными и эффективными, снизив сложность при передаче входных объектов изменений.
Ниже приведен пример запроса с одной переменной.
query($number_of_repos:Int!) {
viewer {
name
repositories(last: $number_of_repos) {
nodes {
name
}
}
}
}
variables {
"number_of_repos": 3
}
Переменные используются в три этапа.
-
Определите переменную вне операции в объекте
variables:variables { "number_of_repos": 3 }Объект должен быть допустимым кодом JSON. В этом примере показана переменная простого типа
Int, но можно определять переменные и более сложных типов, такие как входные объекты. Здесь также можно определить несколько переменных. -
Передайте переменную в операцию в качестве аргумента:
query($number_of_repos:Int!){Аргумент представляет собой пару "ключ-значение", где ключ — это имя, начинающееся с
$(например,$number_of_repos), а значение — это тип (например,Int). Чтобы указать, что тип является обязательным, добавьте!. Если вы определили несколько переменных, включите их здесь как несколько аргументов. -
Используйте переменную в операции:
repositories(last: $number_of_repos) {В этом примере переменная означает количество получаемых репозиториев. Тип указывается на шаге 2, так как в GraphQL действует строгая типизация.
Этот процесс делает аргумент запроса динамическим. Теперь мы можем просто изменить значение в объекте variables, оставив остальную часть запроса без изменений.
Использование переменных в качестве аргументов позволяет динамически обновлять значения в объекте variables, не меняя запрос.
Пример запроса
Давайте рассмотрим более сложный запрос в контексте.
Следующий запрос обращается к репозиторию octocat/Hello-World, находит 20 последних закрытых проблем и возвращает заголовок, URL-адрес и первые пять меток каждой проблемы:
query {
repository(owner:"octocat", name:"Hello-World") {
issues(last:20, states:CLOSED) {
edges {
node {
title
url
labels(first:5) {
edges {
node {
name
}
}
}
}
}
}
}
}
Рассмотрим его структуру построчно.
-
query {Так как мы хотим считать данные с сервера, а не изменить их,
queryявляется корневой операцией. (Если операция не указана,queryтакже выполняется по умолчанию.) -
repository(owner:"octocat", name:"Hello-World") {Сначала нужно найти объект
repository. Проверка схемы показывает, что для этого объекта требуются аргументыownerиname. -
issues(last:20, states:CLOSED) {Чтобы получить сведения о всех проблемах в репозитории, мы вызываем объект
issues. (Мы могли бы запросить одну проблемуissueиз объектаrepository, но для этого нужно знать количество возвращаемых проблем и предоставить его в качестве аргумента.)Некоторые сведения об объекте
issues:- В документации говорится, что этот объект имеет тип
IssueConnection. - Проверка схемы показывает, что в качестве аргумента для этого объекта требуется количество последних (
last) или первых (first) результатов, поэтому мы указываем20. - В документах также говорится, что этот объект принимает
statesаргумент, который являетсяIssueStateперечислением,OPENпринимаюющим илиCLOSEDзначениями. Чтобы найти только закрытые проблемы, мы присваиваем ключуstatesзначениеCLOSED.
- В документации говорится, что этот объект имеет тип
-
edges {Мы знаем, что объект
issues— это соединение, так как он имеет типIssueConnection. Чтобы получить данные по отдельным проблемам, нужно access узел черезedges. -
node {В данном случае мы получаем узлы в конце ребра. В документации по
IssueConnectionуказано, что узел в конце типаIssueConnectionявляется объектомIssue. -
Теперь, когда мы знаем, что извлекаем объект
Issue, мы можем обратиться к документации и указать поля, которые нужно вернуть:title url labels(first:5) { edges { node { name } } }В данном случае мы указываем поля
title,urlиlabelsобъектаIssue.Тип поля
labels—LabelConnection. Как и в случае с объектомissues, так какlabels— это соединение, необходимо пройти по его ребрам к подключенному узлу: объектуlabel. В этом узле можно указать поля объектаlabel, которые нужно вернуть, в данном случаеname.
Вы можете заметить, что выполнение этого запроса в общедоступном Hello-World репозитории Octocat не возвращает много меток. Попробуйте выполнить его в одном из собственных репозиториев, использующих метки, и вы, скорее всего, заметите разницу.
Пример изменения
Для изменений часто требуются сведения, которые можно узнать только путем предварительного выполнения запроса. В этом примере показаны две операции:
- запрос для получения идентификатора проблемы;
- изменение для добавления реакции эмодзи на проблему.
query FindIssueID {
repository(owner:"octocat", name:"Hello-World") {
issue(number:349) {
id
}
}
}
mutation AddReactionToIssue {
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
reaction {
content
}
subject {
id
}
}
}
Разберем этот пример. Задача звучит просто: добавить реакцию эмодзи на проблему.
С какого же запроса нам начать? Пока мы не знаем.
Так как мы хотим изменить данные на сервере (добавить эмодзи к проблеме), мы начинаем с поиска подходящего изменения в схеме. В справочной документации есть изменение addReaction с таким описанием: Adds a reaction to a subject. Отлично!
В документации по изменению перечислены три поля входных данных:
clientMutationId(String)subjectId(ID!)content(ReactionContent!)
Символы ! указывают, что subjectId и content являются обязательными полями. То, что поле content обязательное, разумно: мы хотим добавить реакцию, поэтому нам нужно указать, какой эмодзи следует использовать.
Но почему обязательным является поле subjectId? Это связано с тем, что subjectId — это единственный способ указать, на какую проблему в каком репозитории следует отреагировать.
Вот почему мы начинаем этот пример с запроса: чтобы получить ID.
Давайте разберем запрос построчно.
-
query FindIssueID {Здесь мы выполняем запрос и называем его
FindIssueID. Обратите внимание, что именование запроса является необязательным; мы даем ему имя здесь, чтобы мы могли включить его в то же окно клиента графического интерфейса, что и мутация. -
repository(owner:"octocat", name:"Hello-World") {Мы указываем репозиторий, запрашивая объект
repositoryи передавая аргументыownerиname. -
issue(number:349) {Мы указываем проблему, на которую нужно отреагировать, запрашивая объект
issueи передавая аргументnumber. -
idЗдесь мы получаем
id``https://github.com/octocat/Hello-World/issues/349, чтобы пройти заsubjectId.
При выполнении запроса мы получаем id``MDU6SXNzdWUyMzEzOTE1NTE=.
Примечание.
Возвращаемое id в запросе значение, которое мы передадим в виде subjectID изменения. Ни в документации, ни в схеме эта связь не определена. Необходимо просто понимать, как работают имена.
Зная идентификатор, мы можем перейти к изменению:
-
mutation AddReactionToIssue {Здесь мы выполняем изменение и называем его
AddReactionToIssue. Как и в случае с запросами, именование мутации является необязательным; мы даем ему имя здесь, чтобы мы могли включить его в то же окно клиента с графическим интерфейсом, что и запрос. -
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {Разберем эту строку:
addReaction— это имя изменения.input— это обязательный ключ аргумента. Для изменения это всегдаinput.{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}— это обязательное значение аргумента. Это всегда будет входной объект (отсюда и завитые скобки), состоящий из входных полей (subjectIdиcontentв данном случае) для мутации.
Как узнать, какое значение следует использовать для содержимого? В
addReactionдокументации говорится, что вcontentполе есть типReactionContent, который является enum, потому что в GitHub поддерживаются только определённые эмодзи-реакции. Ниже перечислены допустимые значения для реакций (обратите внимание, что некоторые значения отличаются от соответствующих имен эмодзи).Содержимое Эмодзи +1👍 -1👎 laugh😄 confused😕 heart❤️ hooray🎉 rocket🚀 eyes👀 -
Остальная часть вызова — это объект полезных данных. Здесь мы указываем данные, которые сервер должен вернуть после изменения. В документации по
addReactionопределены три возможных возвращаемых поля:clientMutationId(String)reaction(Reaction!)subject(Reactable!)
В этом примере возвращаются два обязательных поля (
reactionиsubject); оба они имеют обязательные вложенные поля (contentиidсоответственно).
При выполнении изменения ответ будет следующим:
{
"data": {
"addReaction": {
"reaction": {
"content": "HOORAY"
},
"subject": {
"id": "MDU6SXNzdWUyMTc5NTQ0OTc="
}
}
}
}
Вот и все! Проверьте свою reaction на проблему наведя курсор на 🎉 чтобы найти своё имя пользователя.
Последнее замечание: при передаче нескольких полей во входном объекте синтаксис может получиться громоздким. Помочь может помещение полей в переменную. Вот как можно переписать исходное изменение с использованием переменной:
mutation($myVar:AddReactionInput!) {
addReaction(input:$myVar) {
reaction {
content
}
subject {
id
}
}
}
variables {
"myVar": {
"subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
"content":"HOORAY"
}
}
Примечание.
Вы можете заметить, что в значении поля content в предыдущем примере (где оно используется в изменении напрямую) нет кавычек вокруг HOORAY, но при использовании в переменной кавычки есть. Этому есть причина:
- При использовании
contentв изменении напрямую схема предполагает, что значение имеет типReactionContent, который является перечислением, а не строкой. Если добавить кавычки вокруг значения перечисления, при проверке схемы возникнет ошибка, так как кавычки зарезервированы для строк. - При использовании
contentв переменной раздел переменных должен быть допустимым кодом JSON, поэтому кавычки требуются. Проверка схемы правильно интерпретирует типReactionContent, когда переменная передается в изменение во время выполнения.
Дополнительные сведения о различиях между перечислениями и строками см. в официальной спецификации GraphQL.
Дополнительные материалы
При формировании вызовов GraphQL доступно гораздо больше возможностей. Дополнительную информацию можно найти в следующих ресурсах: