协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
use-graphql-api【开发与工程】Interactuar con APIs GraphQL desde la línea de comandos: descubrir esquemas mediante introspección, construir consultas y mutaciones, ejecutarlas con gh api graphql o curl, analizar respuestas con jq, y encadenar operaciones pasando IDs entre llamadas. Úsalo al automatizar Discussions, Issues o Projects de GitHub via GraphQL, al integrarse con cualqu…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Descubrir, construir, ejecutar y encadenar operaciones GraphQL desde la línea de comandos.
github)gh CLI para GitHub)Determinar los tipos, campos, consultas y mutaciones disponibles.
Para GitHub:
# List available query fields
gh api graphql -f query='{ __schema { queryType { fields { name description } } } }' \
| jq '.data.__schema.queryType.fields[] | {name, description}'
# List available mutation fields
gh api graphql -f query='{ __schema { mutationType { fields { name description } } } }' \
| jq '.data.__schema.mutationType.fields[] | {name, description}'
# Inspect a specific type
gh api graphql -f query='{
__type(name: "Repository") {
fields { name type { name kind ofType { name } } }
}
}' | jq '.data.__type.fields[] | {name, type: .type.name // .type.ofType.name}'
Para endpoints genéricos:
# Full introspection query via curl
curl -s -X POST https://api.example.com/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"{ __schema { types { name kind fields { name } } } }"}' \
| jq '.data.__schema.types[] | select(.kind == "OBJECT") | {name, fields: [.fields[].name]}'
Esperado: Salida JSON que lista los tipos, campos o mutaciones disponibles. La respuesta del esquema confirma que el endpoint es accesible y el token de autenticación es válido.
En caso de fallo:
401 Unauthorized — verifica el token; para GitHub, ejecuta gh auth statusCannot query field — el endpoint puede deshabilitar la introspección; consulta su documentación en su lugarDeterminar si tu tarea requiere una consulta (lectura), mutación (escritura) o suscripción (flujo).
| Intención | Operación | Ejemplo |
|---|---|---|
| Recuperar datos | query | Obtener detalles del repositorio, listar discussions |
| Crear/actualizar/eliminar | mutation | Crear una discussion, añadir un comentario |
| Actualizaciones en tiempo real | subscription | Observar nuevos issues (raro en CLI) |
Para operaciones específicas de GitHub, consulta la documentación de la API GraphQL de GitHub.
# Quick check: does the mutation exist?
gh api graphql -f query='{ __schema { mutationType { fields { name } } } }' \
| jq '.data.__schema.mutationType.fields[].name' | grep -i "discussion"
Esperado: Identificación clara de si se necesita una consulta o mutación, más el nombre exacto de la operación (p.ej., createDiscussion, repository).
En caso de fallo:
Construir la consulta o mutación GraphQL con campos, argumentos y variables.
Ejemplo de consulta — recuperar las categorías de discussion de un repositorio:
gh api graphql -f query='
query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
discussionCategories(first: 10) {
nodes { id name }
}
}
}
' -f owner="OWNER" -f repo="REPO" | jq '.data.repository.discussionCategories.nodes'
Ejemplo de mutación — crear una Discussion de GitHub:
gh api graphql -f query='
mutation($repoId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
createDiscussion(input: {
repositoryId: $repoId,
categoryId: $categoryId,
title: $title,
body: $body
}) {
discussion { url number }
}
}
' -f repoId="$REPO_ID" -f categoryId="$CAT_ID" \
-f title="My Discussion" -f body="Discussion body here"
Reglas clave de construcción:
$var: Type!) en lugar de valores en línea para mayor reutilizaciónfirst: N con nodes para conexiones paginadasid a cada selección de objeto — lo necesitarás para el encadenamientoEsperado: Una operación GraphQL sintácticamente válida con variables apropiadas, selecciones de campos y parámetros de paginación.
En caso de fallo:
ID! vs String!)Ejecutar la operación y capturar la respuesta.
GitHub — usando gh api graphql:
# Simple query
gh api graphql -f query='{ viewer { login } }'
# With variables
gh api graphql \
-f query='query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) { id name }
}' \
-f owner="octocat" -f repo="Hello-World"
# With jq post-processing
REPO_ID=$(gh api graphql \
-f query='query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) { id }
}' \
-f owner="OWNER" -f repo="REPO" \
--jq '.data.repository.id')
Endpoint genérico — usando curl:
curl -s -X POST "$GRAPHQL_ENDPOINT" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "$(jq -n \
--arg query 'query { users { id name } }' \
'{query: $query}'
)"
Esperado: Una respuesta JSON con una clave data que contiene los campos solicitados, o un array errors si la operación falló.
En caso de fallo:
errors en la respuesta — lee el mensaje; las causas comunes son permisos faltantes, IDs inválidos o límites de tasadata vacío — la consulta no coincidió con ningún registro; verifica los valores de entradagh auth status y añade alcances con gh auth refresh -s scopeExtraer los datos que necesitas de la respuesta JSON.
# Extract a single value
gh api graphql -f query='{ viewer { login } }' --jq '.data.viewer.login'
# Extract from a list
gh api graphql -f query='
query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
issues(first: 5, states: OPEN) {
nodes { number title }
}
}
}
' -f owner="OWNER" -f repo="REPO" \
--jq '.data.repository.issues.nodes[] | "\(.number): \(.title)"'
# Assign to a variable for later use
CATEGORY_ID=$(gh api graphql -f query='
query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
discussionCategories(first: 20) {
nodes { id name }
}
}
}
' -f owner="OWNER" -f repo="REPO" \
--jq '.data.repository.discussionCategories.nodes[] | select(.name == "Show and Tell") | .id')
Esperado: Valores limpios y extraídos listos para mostrar o asignar a variables de shell.
En caso de fallo:
jq devuelve null — la ruta del campo es incorrecta; envía el JSON en bruto a jq . primero para inspeccionar la estructuraselect() o | first-r a jq para salida de cadena en brutoUsar la salida de una operación como entrada de la siguiente.
# Step A: Get the repository ID
REPO_ID=$(gh api graphql \
-f query='query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) { id }
}' \
-f owner="$OWNER" -f repo="$REPO" \
--jq '.data.repository.id')
# Step B: Get the discussion category ID
CAT_ID=$(gh api graphql \
-f query='query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
discussionCategories(first: 20) {
nodes { id name }
}
}
}' \
-f owner="$OWNER" -f repo="$REPO" \
--jq '.data.repository.discussionCategories.nodes[]
| select(.name == "Show and Tell") | .id')
# Step C: Create the discussion using both IDs
RESULT=$(gh api graphql \
-f query='mutation($repoId: ID!, $catId: ID!, $title: String!, $body: String!) {
createDiscussion(input: {
repositoryId: $repoId,
categoryId: $catId,
title: $title,
body: $body
}) {
discussion { url number }
}
}' \
-f repoId="$REPO_ID" -f catId="$CAT_ID" \
-f title="$TITLE" -f body="$BODY" \
--jq '.data.createDiscussion.discussion')
echo "Created: $(echo "$RESULT" | jq -r '.url')"
Patrón: Siempre extrae campos id en consultas anteriores para que puedan pasarse como variables ID! a mutaciones posteriores.
Esperado: Un flujo de trabajo de múltiples pasos donde cada llamada tiene éxito y los IDs fluyen correctamente entre operaciones.
En caso de fallo:
set -e y verifica cada valor intermedioR_kgDO...); nunca los construyas manualmentesleep 1 entre llamadas o agrupa consultas usando aliasesdata sin errors| Error | Prevención |
|---|---|
Olvidar ! en tipos de variables requeridas | Siempre verifica el esquema para la anulabilidad; la mayoría de los campos de entrada son no nulos (!) |
| Usar IDs REST en GraphQL | GraphQL usa IDs de nodo opacos; recupéralos via GraphQL, no REST |
| No paginar conjuntos de resultados grandes | Usa first/after con pageInfo { hasNextPage endCursor } |
| Hardcodear IDs en lugar de consultarlos | Los IDs difieren entre entornos; siempre consulta dinámicamente |
Ignorar el array errors | Verifica errores incluso cuando data está presente — los errores parciales son posibles |
| Problemas de comillas de shell con JSON anidado | Usa el flag --jq con gh o envía a través de jq por separado |