Autenticarse con GraphQL
Puedes autenticarte en la GraphQL API mediante un personal access token, una GitHub App o una OAuth app.
Autenticación con un personal access token
Si quieres autenticarte con un personal access token, sigue los pasos que se indican en Administración de tokens de acceso personal. Los datos que solicitas determinarán qué ámbitos o permisos necesitarás.
Por ejemplo, seleccione el permiso "issues:read" para leer todas las incidencias de los repositorios a los que tiene acceso el token.
Todos los fine-grained personal access token incluyen acceso de lectura a repositorios públicos. Para acceder a repositorios públicos con un personal access token (classic), selecciona el ámbito "public_repo".
Si el token no tiene los ámbitos o permisos necesarios para acceder a un recurso, la API devolverá un mensaje de error que indica qué ámbitos o permisos necesita el token.
Autenticación con una GitHub App
Si deseas usar la API en nombre de una organización u otro usuario, GitHub recomienda usar un GitHub App. Para atribuir la actividad a la aplicación, puedes hacer que la aplicación se autentique como una instalación de aplicación. Para atribuir la actividad de la aplicación a un usuario, puedes hacer que la aplicación se autentique en nombre de un usuario. En ambos casos, generarás un token que puedes usar para autenticarte en la GraphQL API. Para más información, consulta Registro de una instancia de GitHub App y Acerca de la autenticación con una aplicación de GitHub.
Autenticación con OAuth app
Para autenticarte con un token de OAuth desde OAuth app, primero debes autorizar OAuth app mediante un flujo de aplicación web o un flujo de dispositivo. A continuación, puedes usar el token de acceso que recibiste para acceder a la API. Para más información, consulta Creación de una aplicación de OAuth y Autorización de aplicaciones de OAuth.
Terminal de GraphQL
La API REST tiene numerosos puntos de conexión. Con GraphQL API, el punto de conexión permanece constante sin importar la operación que realices. Para GitHub Enterprise Server, ese punto de conexión es:
http(s)://HOSTNAME/api/graphql
Comunicarse con GraphQL
Como las operaciones de GraphQL constan de código JSON de varias líneas, GitHub recomienda usar el Explorador para realizar llamadas a GraphQL. También puedes utilizar curl
o cualquier otra biblioteca que entienda HTTP.
En REST, los verbos HTTP determinan la operación realizada. En GraphQL, tendrá que proporcionar un cuerpo codificado con JSON cuando realice una consulta o una mutación, por lo que el verbo HTTP es POST
. La excepción es una consulta de introspección, que es una GET
sencilla al punto de conexión. Para obtener más información sobre las diferencias entre GraphQL y REST, consulta Migrar desde Rest hacia GraphQL.
Para consultar GraphQL mediante un comando curl
, realiza una solicitud POST
con una carga JSON. La carga debe contener una cadena denominada query
:
curl -H "Authorization: bearer TOKEN" -X POST -d " \
{ \
\"query\": \"query { viewer { login }}\" \
} \
" http(s)://HOSTNAME/api/graphql
Note
El valor de cadena de "query"
debe aplicar escape a los caracteres de nueva línea o el esquema no lo analizará correctamente. Para el cuerpo POST
, use comillas dobles externas y comillas dobles interiores con escape.
Acerca de las operaciones de consulta y mutación
Los dos tipos de operaciones permitidas en GraphQL API de GitHub son las consultas y las mutaciones. Si se compara GraphQL con REST, las consultas funcionan como solicitudes GET
, mientras que las mutaciones funcionan comoPOST
/PATCH
/DELETE
. El nombre de la mutación determina qué modificación se ejecuta.
Para obtener información sobre la limitación de tasas, consulta Límites de volumen y límites de nodo para GraphQL API.
Las consultas y mutaciones comparten formatos similares con algunas diferencias importantes.
Acerca de las consultas
Las consultas de GraphQL devuelven solo los datos que especifique. Para crear una consulta, debe especificar campos dentro de campos (también denominados subcampos anidados) hasta que solo se devuelvan valores escalares.
Las consultas se estructuran de esta manera:
query { JSON-OBJECT-TO-RETURN }
Para obtener un ejemplo real, lee Consulta de ejemplo.
Acerca de las mutaciones
Para formar una mutación, debes especificar tres cosas:
- Nombre de la mutación. El Tipo de modificación que quieres realizar.
- Objeto de entrada. Los datos que quiere enviar al servidor, formados por campos de entrada. Pásalo como un argumento al nombre de la mutación.
- Objeto de carga. Los datos que quiere devolver desde el servidor, formados por campos devueltos. Pásalos como el cuerpo del nombre de la mutación.
Las mutaciones se estructuran de la siguiente forma:
mutation { MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) { MUTATION-NAME-PAYLOAD } }
El objeto de entrada de este ejemplo es MutationNameInput
y el objeto de carga es MutationNamePayload
.
En la referencia de mutaciones, los campos de entrada enumerados son lo que se pasa como objeto de entrada. Los campos devueltos enumerados son lo que se pasa como objeto de carga.
Para obtener un ejemplo real, consulta Mutación de ejemplo.
Trabajo con variables
Lasvariables pueden hacer que las consultas sean más dinámicas y eficaces, y pueden reducir la complejidad al pasar objetos de entrada de mutación.
Note
Si usas el Explorador, asegúrate de escribir variables en el panel Query Variables independiente y no incluyas la palabra variables
antes del objeto JSON.
Aquí hay una consulta de ejemplo con una sola variable:
query($number_of_repos:Int!) {
viewer {
name
repositories(last: $number_of_repos) {
nodes {
name
}
}
}
}
variables {
"number_of_repos": 3
}
Hay tres pasos para utilizar las variables:
-
Defina la variable fuera de la operación en un objeto
variables
:variables { "number_of_repos": 3 }
El objeto debe ser un JSON válido. En este ejemplo se muestra un tipo de variable
Int
sencillo, pero se pueden definir tipos de variable más complejos, como los objetos de entrada. También puedes definir variables múltiples aquí. -
Pasa la variable a la operación como un argumento:
query($number_of_repos:Int!){
El argumento es un par clave-valor, donde la clave es el nombre que empieza por
$
(por ejemplo,$number_of_repos
) y el valor es el tipo (por ejemplo,Int
). Agregue!
para indicar si el tipo es obligatorio. Si has identificado variables múltiples, inclúyelas aquí como argumentos múltiples. -
Utiliza la variable dentro de la operación:
repositories(last: $number_of_repos) {
En este ejemplo, sustituimos la variable por la cantidad de repositorios a devolver. Especificamos un tipo en el paso 2, ya que GraphQL requiere de una escritura inflexible.
Este proceso hace dinámico al argumento de la consulta. Ahora se puede cambiar el valor en el objeto variables
y mantener el resto de la consulta igual.
El uso de variables como argumentos permite actualizar los valores del objeto variables
de forma dinámica sin cambiar la consulta.
Ejemplo de consulta
Analicemos una consulta más compleja y pongamos esta información en contexto.
La consulta siguiente examina el repositorio octocat/Hello-World
, busca las 20 incidencias cerradas más recientes y devuelve el título, la dirección URL y las 5 primeras etiquetas de cada incidencia:
query {
repository(owner:"octocat", name:"Hello-World") {
issues(last:20, states:CLOSED) {
edges {
node {
title
url
labels(first:5) {
edges {
node {
name
}
}
}
}
}
}
}
}
Analizando la composición línea por línea:
-
query {
Como el objetivo es leer datos del servidor, no modificarlos, la operación raíz es
query
. (Si no especifica una operación,query
también es el valor predeterminado). -
repository(owner:"octocat", name:"Hello-World") {
Para comenzar la consulta, se busca un objeto
repository
. La validación del esquema indica que este objeto necesita unowner
y un argumentoname
. -
issues(last:20, states:CLOSED) {
Para tener en cuenta todas las incidencias del repositorio, se llama al objeto
issues
. (Se podría consultar un únicoissue
enrepository
, pero para eso sería necesario conocer el número de la incidencia que se quiere devolver y proporcionarlo como argumento).Algunos detalles sobre el objeto
issues
:- En la documentación se indica que este objeto tiene el tipo
IssueConnection
. - La validación del esquema indica que este objeto necesita un número de resultados
last
ofirst
como argumento, por lo que se proporciona20
. - En la documentación también se indica que este objeto acepta un argumento
states
, que es una enumeraciónIssueState
que acepta valoresOPEN
oCLOSED
. Para busca solo incidencias cerradas, se asigna un valor deCLOSED
a la clavestates
.
- En la documentación se indica que este objeto tiene el tipo
-
edges {
Se sabe que
issues
es una conexión porque tiene el tipoIssueConnection
. Para recuperar datos sobre incidencias individuales, es necesario al nodo por medio deedges
. -
node {
Aquí devolvemos el nodo al final del borde. En la documentación de
IssueConnection
se indica que el nodo al final del tipoIssueConnection
es un objetoIssue
. -
Ahora que se sabe que se va a recuperar un objeto
Issue
, se puede examinar la documentación y especificar los campos que se quieren devolver:title url labels(first:5) { edges { node { name } } }
Aquí se especifican los campos
title
,url
ylabels
del objetoIssue
.El campo
labels
tiene el tipoLabelConnection
. Como sucede con el objetoissues
, comolabels
es una conexión, es necesario desplazar sus bordes a un nodo conectado: el objetolabel
. En el nodo, se pueden especificar los campos del objetolabel
que se quieren devolver, en este caso,name
.
Es posible que observe que la ejecución de esta consulta en el repositorio Hello-World
de Octocat no devuelve muchas etiquetas. Intenta ejecutarlo en uno de tus propios repositorios que utilice etiquetas, y seguramente verás la diferencia.
Mutación de ejemplo
Las mutaciones a menudo requieren información que solo puedes encontrar si realizas una consulta primero. Este ejemplo muestra dos operaciones:
- Una consulta para obtener la ID de un informe de problemas.
- Una mutación para agregar una reacción de emoji a dicho informe.
query FindIssueID {
repository(owner:"octocat", name:"Hello-World") {
issue(number:349) {
id
}
}
}
mutation AddReactionToIssue {
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
reaction {
content
}
subject {
id
}
}
}
Tip
Aunque puede incluir una consulta y una mutación en la misma ventana del Explorador si les asigna nombres (FindIssueID
y AddReactionToIssue
en este ejemplo), las operaciones se ejecutarán como llamadas independientes al punto de conexión de GraphQL. No se puede realizar una consulta al mismo tiempo que una mutación, o viceversa.
Analicemos el ejemplo. La tarea parece simple: agregar una reacción de emoji a un informe de problemas.
Así que, ¿qué es lo que sabemos para comenzar con la consulta? Aún no sabemos nada.
Ya que queremos modificar los datos en el servidor (agregar un emoji a un informe de problemas), comenzamos buscando el modelo para una mutación útil. En la documentación de referencia se muestra la mutación addReaction
, con esta descripción: Adds a reaction to a subject.
Perfecto.
Los documentos para la mutación listan tres campos de entrada:
clientMutationId
(String
)subjectId
(ID!
)content
(ReactionContent!
)
Los valores !
indican que subjectId
y content
son campos obligatorios. Un campo content
obligatorio tiene sentido: el objetivo es agregar una reacción, por lo que será necesario especificar el emoji que se va a usar.
¿Pero por qué subjectId
es obligatorio? Se debe a que subjectId
es la única manera de identificar a qué incidencia de qué repositorio se debe reaccionar.
Este es el motivo de comenzar el ejemplo con una consulta: para obtener ID
.
Examinemos la consulta línea por línea:
-
query FindIssueID {
Aquí se realiza una consulta y se le asigna el nombre
FindIssueID
. Nota que el nombrar una consulta es opcional; le dimos un nombre para que podamos incluirlo en la misma ventana del explorador que utiliza la mutación. -
repository(owner:"octocat", name:"Hello-World") {
Para especificar el repositorio se consulta el objeto
repository
y se pasan los argumentosowner
yname
. -
issue(number:349) {
Para especificar la incidencia a la que reaccionar se consulta el objeto
issue
y se pasa un argumentonumber
. -
id
Aquí es donde se recupera el valor
id
dehttps://github.com/octocat/Hello-World/issues/349
para pasarlo comosubjectId
.
Cuando se ejecuta la consulta, se obtiene id
: MDU6SXNzdWUyMzEzOTE1NTE=
.
Note
El valor id
devuelto en la consulta es el que se pasará como subjectID
en la mutación. Ni los docs ni la introspección de modelo indicarán esta relación; necesitarás entender los conceptos detrás de los nombres para averiguarla.
Una vez conociendo la ID, podemos proceder con la mutación:
-
mutation AddReactionToIssue {
Aquí se ejecuta una mutación y se le asigna el nombre
AddReactionToIssue
. Como con las consultas, nombrar una mutación es opcional; le dimos un nombre para poder incluirlo en la misma ventana del explorador que la consulta. -
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
Examinemos esta línea:
addReaction
es el nombre de la mutación.input
es la clave de argumento obligatoria. Para una mutación siempre seráinput
.{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}
es la valor de argumento obligatorio. Siempre será un objeto de entrada (de ahí las llaves) formado por campos de entrada (subjectId
ycontent
en este caso) para una mutación.
¿Cómo sabemos qué valor utilizar para el contenido? En la documentación de
addReaction
se indica que el campocontent
tiene el tipoReactionContent
, que es una enumeración porque en las incidencias de GitHub solo se admiten ciertas de reacciones emoji. Estos son los valores permitidos para las reacciones (nota que algunos valores son diferentes de sus nombres de emoji correspondientes):Contenido Emoji +1
👍 -1
👎 laugh
😄 confused
😕 heart
❤️ hooray
🎉 rocket
🚀 eyes
👀 -
El resto del llamado se compone del objeto de carga útil. Aquí es donde especificamos los datos que queremos recuperar del servidor después de que realicemos la mutación. Estas líneas proceden de la documentación de
addReaction
, con tres campos devueltos posibles:clientMutationId
(String
)reaction
(Reaction!
)subject
(Reactable!
)
En este ejemplo, se devuelven los dos campos obligatorios (
reaction
ysubject
), que tienen subcampos obligatorios (content
yid
, respectivamente).
Cuando ejecutamos la mutación, esta es la respuesta:
{
"data": {
"addReaction": {
"reaction": {
"content": "HOORAY"
},
"subject": {
"id": "MDU6SXNzdWUyMTc5NTQ0OTc="
}
}
}
}
Eso es todo. Para consultar la reacción a la incidencia mantenga el mouse sobre 🎉 para encontrar el nombre de usuario.
Una última nota: cuando pasas varios campos en un objeto de entrada, la sintaxis puede ser difícil de manejar. Puede resultar útil mover los campos a una variable. Así es como podrías reescribir la mutación original utilizando una variable:
mutation($myVar:AddReactionInput!) {
addReaction(input:$myVar) {
reaction {
content
}
subject {
id
}
}
}
variables {
"myVar": {
"subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
"content":"HOORAY"
}
}
Note
Es posible que observe que el valor del campo content
en el ejemplo anterior (donde se usa directamente en la mutación) no tiene comillas alrededor de HOORAY
, pero sí cuando se usa en la variable. Esto es por una razón:
- Cuando se usa
content
directamente en la mutación, el esquema espera que el valor sea de tipoReactionContent
, que es una enumeración, no una cadena. La validación del modelo arrojará un error si agregas comillas antes y después del valor de enumerador, ya que éstas están reservadas para las cadenas. - Cuando se usa
content
en una variable, la sección de variables debe ser código JSON válido, por lo que las comillas son obligatorias. La validación del esquema interpreta correctamente el tipoReactionContent
cuando la variable se pasa a la mutación durante la ejecución.
Para más información sobre la diferencia entre enumeraciones y cadenas, vea la especificación oficial de GraphQL.
Información adicional
Hay mucho más que puede hacer al realizar llamadas a GraphQL. Aquí hay algunos lugares que te pueden interesar posteriormente: