¡Estás interesado en integrarte con la plataforma de GitHub? Estás en las manos correctas. Esta guía te ayudará a crear una app que proporcione la mejor de las experiencias para tus usuarios y que garantice su confiabilidad al interactuar con la API.
Asegura las cargas útiles que se entregen desde GitHub
Es muy importante que asegures las cargas útiles que se envíen desde GitHub. Aunque en una carga útil jamás se transmita información personal (como las contraseñas), no es bueno filtrar ninguna información. Algunos de los tipos de información que pudieran ser sensibles incluyen las direcciones de correo electrónico del confirmante o los nombres de los repositorios privados.
Hya varios pasos que puedes tomar para asegurar la recepción de las cárgas útiles que GitHub entregue:
- Asegúrate de que tu servidor receptor tenga una conexión HTTPS. Predeterminadamente, GitHub verificará los certificados SSl cuando entregue las cargas útiles.
- Proporciona un token secreto para garantizar que las cargas útiles vengan de GitHub definitivamente. Al requerir un token secreto, te estás asegurando de que ninguno de los datos que recibe tu servidor viene de GitHub en lo absoluto. Idealmente, deberías proporcionar un token secreto diferente por cada usuario de tu servicio. Así, si un token se pone en riesgo, nadie más se vería afectado.
Favorece el trabajo asincrónico sobre el sincronizado
GitHub espera que las integraciones respondan dentro de los primeros 30 segundos de que se reciba la carga útil del webhook. Si tu servicio demora más que eso para completarse, entonces GitHub finaliza la conexión y se pierde la carga útil.
Ya que es imposible predecir qué tan rápido completará esto tu servidor, deberías hacer todo "el trabajo real" en un job que actúe en segundo plano. Resque (para Ruby), RQ (para Python), o RabbitMQ (para JAVA) son algunos ejemplos de bibliotecas que pueden manejar jobs de segundo plano para procesamiento y formación en cola.
Nota que, aún si tienes un job ejecutándose en segundo plano, GitHub sigue esperando que tu servidor responda dentro de veinte segundos. Tu servidor necesita reconocer que recibió la carga útil mediante el envío de algún tipo de respuesta. Es crítico que tu servicio realice cualquier validación de una carga útil tan pronto sea posible, para que puedas reportar con exactitud si tu servidor continuará con la solicitud o no.
Utiliza códigos de estado de HTTP adecuados cuando respondas a GitHub
Cada webhook tiene su propia sección de "Entregas Recientes", la cual lista si los despliegues tuvieron éxito o no.
Deberías utilizar códigos de estado de HTTP adecuados para informar a los usuarios. Puedes utilizar códigos como el 201
o el 202
para reconocer la recepción de las cargas útiles que no se van a procesar (por ejemplo, una carga útil que entregue una rama que no sea la predeterminada). Reserva el código de error 500
para las fallas catastróficas.
Proporciona al usuario tanta información como sea posible
Los usuarios pueden profundizar en las respuestas del servidor que envíes de vuelta a GitHub. Asegúrate de que tus mensajes son claros e informativos.
Sigue cualquier redireccionamiento que te envíe la API
GitHub es muy explícito en decirte cuando un recurso se migró y lo hace proporcionándote un código de estado de redirección. Debes seguir estas redirecciones. Cada respuesta de redirección configura el encabezado Location
con la URI nueva a la cual debes dirigirte. Si recibes una redirección, es mejor que actualices tu código para seguir a la nueva URI, en caso de que estés utilizando una ruta obsoleta que tal ves eliminemos.
Hemos proporcionado una lista de códigos de estado de HTTP que puedes consultar cuando estés diseñando tu app para seguir las redirecciones.
No analices las URL manualmente
A menudo, las respuestas a la API contienen datos en forma de URL. Por ejemplo, cuando solicitamos un repositorio, estamos enviando una clave denominada clone_url
con la URL que puedes utilizar para clonar el repositorio.
Para mantener la estabilidad de tu app, no deberías analizar estos datos o tratr de adivinar y construir el formato de las URL futuras. Tu app puede fallar si decidimos cambiar la URL.
Por ejemplo, cuando estamos trabajando con resultados paginados, a menudo es tentador construir las URL que adjunten ?page=<number>
al final. Evita esa tentación. Nuestra guía sobre paginación te ofrece tips de seguridad sobre cómo seguir resultados paginados de manera confiable.
Verifica el tipo de evento y de acción antes de procesar el evento
Hay varios tipos de eventos de webhook, y cada evento puede tener varias acciones. En medida en que el conjunto de características de GitHub crece, de vez en cuando agregaremos tipos de evento para nuevas acciones a los tipos de evento existentes. Asegúrate de que tu aplicación verifique el tipo y acción de un evento explícitamente antes de que hagas cualquier procesamiento de webhook. El encabezado de solicitud de X-GitHub-Event
puede utilizarse para saber qué evento se recibió, para que el procesamiento se pueda gestionar de manera adecuada. De manera similar, la carga útil tiene una clave de action
de alto nivel que puede utilizarse para saber qué acción se llevó a cabo en el objeto relevante.
Por ejemplo, si configuraste un webhook de GitHub para "Enviarme todo", tu aplicación comenzará a recibir tipos de evento y acciones nuevos conforme se agreguen. Por lo tanto, no se recomienda utilizar ningún tipo de cláusula "else" que reciba todo. Toma como ejemplo el siguiente extracto de código:
# Not recommended: a catch-all else clause
def receive
event_type = request.headers["X-GitHub-Event"]
payload = request.body
case event_type
when "repository"
process_repository(payload)
when "issues"
process_issues(payload)
else
process_pull_requests
end
end
En este ejemplo, se llamará correctamente a los métodos de process_repository
y process_issues
si se recibió un evento de repository
o de issues
. Sin embargo, cualquier otro tipo de evento resultaría en que se llamara a process_pull_requests
. En medida en que se agreguen tipos de evento nuevos, esto dará como resultado un comportamiento incorrecto y los tipos de evento nuevos se procesarían de la misma forma que se haría con un evento de pull_request
.
En vez de esto, te sugerimos revisar los tipos de evento explícitamente y tomar acciones adecuadas para cada caso. En el siguiente ejemplo, estamos verificando explícitamente si hay eventos de pull_request
y la cláusula else
simplemente registra lo que recibimos en un tipo de evento nuevo:
# Recommended: explicitly check each event type
def receive
event_type = request.headers["X-GitHub-Event"]
payload = JSON.parse(request.body)
case event_type
when "repository"
process_repository(payload)
when "issues"
process_issue(payload)
when "pull_request"
process_pull_requests(payload)
else
puts "Oooh, something new from GitHub: #{event_type}"
end
end
Ya que cada evento puede tener acciones múltiples también, se recomienda que las acciones se verifiquen de forma similar. Por ejemplo, el IssuesEvent
tiene muchas acciones posibles. Estas incluyen a opened
cuando se crea el informe de problemas, a closed
cuando el informe de problemas se cierra, y a assigned
cuando este informe se asigna a alguien.
De la misma forma como agregamos tipos de evento, podemos agregar acciones nuevas a los eventos existentes. Por lo tanto, nuevamente no se recomienda utilizar ningún tipo de cláusula "else" para recibir todo cuando verificamos la acción de un evento. En vez de esto, te sugerimos verificar las acciones de evento explícitamente como lo hicimos con el tipo de evento. Un ejemplo de esto se ve muy similar a lo que sugerimos para los tipos de evento anteriormente:
# Recommended: explicitly check each action
def process_issue(payload)
case payload["action"]
when "opened"
process_issue_opened(payload)
when "assigned"
process_issue_assigned(payload)
when "closed"
process_issue_closed(payload)
else
puts "Oooh, something new from GitHub: #{payload["action"]}"
end
end
En este ejemplo, la acción closed
se verifica primero antes de llamar al método process_closed
. Cualquier acción sin identificar se registra para referencias futuras.
Lidiar con los errores de la API
Aunque tu código jamás introducirá un error, podrías encontrarte con que has dado con varios errores sucesivos cuando intentas acceder a la API.
En vez de ignorar los códigos de estado 4xx
y 5xx
repetidamente, debes asegurarte de que estás interactuando correctamente con la API. Por ejemplo, si una terminal solicita una secuencia y estás pasando un valor numérico, vas a recibir un error de validación 5xx
, y tu llamada no tendrá éxito. De forma similar, el intentar acceder a una terminal inexistente o no autorizada dará como resultado un error 4xx
.
El ignorar los errores de validación constantes a propóstio podría resultar en la suspensión de tu app por abuso.