Skip to main content

Lidar com entregas de webhook

Saiba como escrever código para ouvir e responder a entregas de webhooks.

Introdução

Ao criar um webhook, você especifica um URL e assina tipos de eventos. Quando ocorrer um evento no qual seu webhook está inscrito, o GitHub enviará uma solicitação HTTP com dados sobre o evento para o URL que você especificou. Se o seu servidor estiver configurado para ouvir entregas de webhooks nesse URL, ele poderá agir quando receber um.

Este artigo descreve como escrever código para permitir que seu servidor ouça e responda a entregas de webhooks. Você testará seu código usando seu computador ou codespace como um servidor local.

Instalação

Para testar seu webhook localmente, você pode usar um URL proxy de webhook para encaminhar webhooks do GitHub para seu computador ou codespace. Este artigo usa o smee.io para fornecer um URL de proxy de webhook e encaminhar webhooks.

Obter a URL de proxy de webhook

  1. No navegador, navegue até https://smee.io/.
  2. Clique em Iniciar um novo canal.
  3. Copie a URL completa em "URL de Proxy de Webhook". Você usará esse URL nas etapas de configuração a seguir.

Encaminhar webhooks

  1. Se você ainda não tiver o smee-client instalado, execute o seguinte comando no seu terminal:

    Shell
    npm install --global smee-client
    
  2. Para receber webhooks encaminhados de smee.io, execute o seguinte comando em seu terminal. Substitua WEBHOOK_PROXY_URL pela URL de proxy de webhook anterior.

    Shell
    smee --url WEBHOOK_PROXY_URL --path /webhook --port 3000
    

    Você deverá ver uma saída semelhante a esta, em que WEBHOOK_PROXY_URL é a URL de proxy de webhook:

    Shell
    Forwarding WEBHOOK_PROXY_URL to http://127.0.0.1:3000/webhook
    Connected WEBHOOK_PROXY_URL
    

    Observe que o caminho é /webhook e a porta é 3000. Você usará esses valores posteriormente quando escrever o código para lidar com entregas de webhooks.

  3. Mantenha isso em execução enquanto você testa seu webhook. Quando quiser interromper o encaminhamento de webhooks, pressione Ctrl+C .

Criar um webhook

  1. Crie um webhook com as seguintes configurações. Para saber mais, confira Criar webhooks.

    • Para o URL, use o URL do proxy do webhook que você usou anteriormente.
    • Se tiver a opção de escolher o tipo de conteúdo, use JSON.

Escrever código para lidar com entregas de webhooks

Para lidar com entregas de webhooks, você precisa escrever um código que faça o seguinte:

  • Inicialize seu servidor para escutar as solicitações ao URL do webhook
  • Leia os cabeçalhos e o corpo HTTP da solicitação
  • Realize a ação desejada em resposta à solicitação

Você pode usar qualquer linguagem de programação que possa ser executada no seu servidor.

Os exemplos a seguir imprimem uma mensagem quando uma entrega de webhook é recebida. No entanto, você pode modificar o código para executar outra ação, como fazer uma solicitação à API do GitHub ou enviar uma mensagem do Slack.

Exemplo do Ruby

Este exemplo usa uma gem do Ruby, o Sinatra, para definir rotas e lidar com solicitações HTTP. Para obter mais informações, confira o LEIAME do Sinatra.

Exemplo com Ruby: Instalar dependências

Para usar este exemplo, você deve instalar a gem Sinatra no seu projeto Ruby. Por exemplo, faça isso com o Bundler:

  1. Caso ainda não tenha o Bundler instalado, execute o seguinte comando no terminal:

    Shell
    gem install bundler
    
  2. Caso ainda não tenha um Gemfile para seu aplicativo, execute o seguinte comando no terminal:

    Shell
    bundle init
    
  3. Caso ainda não tenha um Gemfile.lock para seu aplicativo, execute o seguinte comando no terminal:

    Shell
    bundle install
    
  4. Instale a gem Sinatra executando o seguinte comando em seu terminal:

    Shell
    bundle add sinatra
    

Exemplo com Ruby: Escrever o código

Crie um arquivo Ruby com o seguinte conteúdo. Modifique o código para lidar com os tipos de eventos nos quais seu webhook está inscrito, bem como o evento ping que o GitHub envia quando você cria um webhook. Este exemplo lida com os eventos issues e ping.

Ruby
require 'sinatra'
require 'json'

These are the dependencies for this code. You installed the sinatra gem earlier. For more information, see "Ruby example: Install dependencies." The json library is a standard Ruby library, so you don't need to install it.

post '/webhook' do

The /webhook route matches the path that you specified for the smee.io forwarding. For more information, see "Forward webhooks."

Once you deploy your code to a server and update your webhook URL, you should change this to match the path portion of the URL for your webhook.

  status 202

Respond to indicate that the delivery was successfully received. Your server should respond with a 2XX response within 10 seconds of receiving a webhook delivery. If your server takes longer than that to respond, then GitHub terminates the connection and considers the delivery a failure.

  github_event = request.env['HTTP_X_GITHUB_EVENT']

Check the X-GitHub-Event header to learn what event type was sent. Sinatra changes X-GitHub-Event to HTTP_X_GITHUB_EVENT.

  if github_event == "issues"
    data = JSON.parse(request.body.read)
    action = data['action']
    if action == "opened"
      puts "An issue was opened with this title: #{data['issue']['title']}"
    elsif action == "closed"
      puts "An issue was closed by #{data['issue']['user']['login']}"
    else
      puts "Unhandled action for the issue event: #{action}"
    end
  elsif github_event == "ping"
    puts "GitHub sent the ping event"
  else
    puts "Unhandled event: #{github_event}"
  end
end

You should add logic to handle each event type that your webhook is subscribed to. For example, this code handles the issues and ping events.

If any events have an action field, you should also add logic to handle each action that you are interested in. For example, this code handles the opened and closed actions for the issue event.

For more information about the data that you can expect for each event type, see "Eventos e cargas de webhook."

# These are the dependencies for this code. You installed the `sinatra` gem earlier. For more information, see "[Ruby example: Install dependencies](#ruby-example-install-dependencies)." The `json` library is a standard Ruby library, so you don't need to install it.
require 'sinatra'
require 'json'

# The `/webhook` route matches the path that you specified for the smee.io forwarding. For more information, see "[Forward webhooks](#forward-webhooks)."
#
# Once you deploy your code to a server and update your webhook URL, you should change this to match the path portion of the URL for your webhook.
post '/webhook' do

  # Respond to indicate that the delivery was successfully received.
  # Your server should respond with a 2XX response within 10 seconds of receiving a webhook delivery. If your server takes longer than that to respond, then GitHub terminates the connection and considers the delivery a failure.
  status 202

  # Check the `X-GitHub-Event` header to learn what event type was sent.
  # Sinatra changes `X-GitHub-Event` to `HTTP_X_GITHUB_EVENT`.
  github_event = request.env['HTTP_X_GITHUB_EVENT']

  # You should add logic to handle each event type that your webhook is subscribed to.
  # For example, this code handles the `issues` and `ping` events.
  #
  # If any events have an `action` field, you should also add logic to handle each action that you are interested in.
  # For example, this code handles the `opened` and `closed` actions for the `issue` event.
  #
  # For more information about the data that you can expect for each event type, see "[AUTOTITLE](/webhooks/webhook-events-and-payloads)."
  if github_event == "issues"
    data = JSON.parse(request.body.read)
    action = data['action']
    if action == "opened"
      puts "An issue was opened with this title: #{data['issue']['title']}"
    elsif action == "closed"
      puts "An issue was closed by #{data['issue']['user']['login']}"
    else
      puts "Unhandled action for the issue event: #{action}"
    end
  elsif github_event == "ping"
    puts "GitHub sent the ping event"
  else
    puts "Unhandled event: #{github_event}"
  end
end

Exemplo com Ruby: Testar o código

Para testar seu webhook, você pode usar seu computador ou codespace para atuar como um servidor local. Se tiver problemas com essas etapas, consulte Solução de problemas.

  1. Certifique-se de que esteja encaminhando webhooks. Se não estiver mais encaminhando webhooks, siga as etapas em Encaminhar webhooks novamente.

  2. Em uma janela de terminal separada, execute o seguinte comando para iniciar um servidor local em seu computador ou codespace. Substitua FILE_PATH pelo caminho para o arquivo em que o código da seção anterior está armazenado. Observe que PORT=3000 corresponde à porta que você especificou para o encaminhamento do webhook na etapa anterior.

    Shell
    PORT=3000 ruby FILE_NAME
    

    Você deverá ver um resultado que indica algo como "Sinatra has taken the stage on 3000".

  3. Acione seu webhook. Por exemplo, se você criou um webhook de repositório que está inscrito no evento issues, abra um problema em seu repositório. Você também pode reenviar uma entrega anterior de webhook. Para saber mais, confira Entregar webhooks novamente.

  4. Navegue até a URL de proxy de webhook no smee.io. Você deverá ver um evento que corresponde ao evento que acionou ou reenviou. Isso indica que o GitHub enviou com êxito uma entrega de webhook ao URL do conteúdo que você especificou.

  5. Na janela do terminal em que smee --url WEBHOOK_PROXY_URL --path /webhook --port 3000 foi executado, você deverá ver algo como POST http://127.0.0.1:3000/webhook - 202. Isso indica que o smee encaminhou com êxito seu webhook ao servidor local.

  6. Na janela do terminal em que PORT=3000 ruby FILE_NAME foi executado, você deverá ver uma mensagem correspondente ao evento que foi enviado. Por exemplo, se você usar o código de exemplo acima e reenviar o evento ping, deverá ver "GitHub enviou o evento de ping". Você também pode ver algumas outras linhas que o Sinatra imprime automaticamente.

  7. Em ambas as janelas de terminal, pressione Ctrl+C para interromper o servidor local e parar de escutar os webhooks encaminhados.

Agora que o código já foi testado localmente, você pode fazer alterações para usar o webhook em produção. Para saber mais, confira as Próximas etapas. Se teve problemas para testar o código, tente as etapas em Solução de problemas.

Exemplo de JavaScript

Este exemplo usa o Node.js e a biblioteca Express para definir rotas e lidar com solicitações HTTP. Para obter mais informações, confira: expressjs.com.

Para obter um exemplo que utiliza o SDK Octokit.js do GitHub, confira Criar um Aplicativo GitHub que responde a eventos de webhook.

Este exemplo exige que seu computador ou codespace execute o Node.js versão 12 ou superior e o npm versão 6.12.0 ou superior. Para obter mais informações, confira Node.js.

Exemplo com JavaScript: instalar dependências

Para usar este exemplo, você deve instalar a biblioteca express em seu projeto Node.js. Por exemplo:

Shell
npm install express

Exemplo de JavaScript: escrever o código

Crie um arquivo JavaScript com os conteúdos a seguir: Modifique o código para lidar com os tipos de eventos nos quais seu webhook está inscrito, bem como o evento ping que o GitHub envia quando você cria um webhook. Este exemplo lida com os eventos issues e ping.

JavaScript
const express = require('express');

You installed the express library earlier. For more information, see "JavaScript example: Install dependencies."

const app = express();

This initializes a new Express application.

app.post('/webhook', express.json({type: 'application/json'}), (request, response) => {

This defines a POST route at the /webhook path. This path matches the path that you specified for the smee.io forwarding. For more information, see "Forward webhooks."

Once you deploy your code to a server and update your webhook URL, you should change this to match the path portion of the URL for your webhook.

  response.status(202).send('Accepted');

Respond to indicate that the delivery was successfully received. Your server should respond with a 2XX response within 10 seconds of receiving a webhook delivery. If your server takes longer than that to respond, then GitHub terminates the connection and considers the delivery a failure.

  const githubEvent = request.headers['x-github-event'];

Check the x-github-event header to learn what event type was sent.

  if (githubEvent === 'issues') {
    const data = request.body;
    const action = data.action;
    if (action === 'opened') {
      console.log(`An issue was opened with this title: ${data.issue.title}`);
    } else if (action === 'closed') {
      console.log(`An issue was closed by ${data.issue.user.login}`);
    } else {
      console.log(`Unhandled action for the issue event: ${action}`);
    }
  } else if (githubEvent === 'ping') {
    console.log('GitHub sent the ping event');
  } else {
    console.log(`Unhandled event: ${githubEvent}`);
  }
});

You should add logic to handle each event type that your webhook is subscribed to. For example, this code handles the issues and ping events.

If any events have an action field, you should also add logic to handle each action that you are interested in. For example, this code handles the opened and closed actions for the issue event.

For more information about the data that you can expect for each event type, see "Eventos e cargas de webhook."

const port = 3000;

This defines the port where your server should listen. 3000 matches the port that you specified for webhook forwarding. For more information, see "Forward webhooks."

Once you deploy your code to a server, you should change this to match the port where your server is listening.

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

This starts the server and tells it to listen at the specified port.

// You installed the `express` library earlier. For more information, see "[JavaScript example: Install dependencies](#javascript-example-install-dependencies)."
const express = require('express');

// This initializes a new Express application.
const app = express();

// This defines a POST route at the `/webhook` path. This path matches the path that you specified for the smee.io forwarding. For more information, see "[Forward webhooks](#forward-webhooks)."
//
// Once you deploy your code to a server and update your webhook URL, you should change this to match the path portion of the URL for your webhook.
app.post('/webhook', express.json({type: 'application/json'}), (request, response) => {

  // Respond to indicate that the delivery was successfully received.
  // Your server should respond with a 2XX response within 10 seconds of receiving a webhook delivery. If your server takes longer than that to respond, then GitHub terminates the connection and considers the delivery a failure.
  response.status(202).send('Accepted');

  // Check the `x-github-event` header to learn what event type was sent.
  const githubEvent = request.headers['x-github-event'];

  // You should add logic to handle each event type that your webhook is subscribed to.
  // For example, this code handles the `issues` and `ping` events.
  //
  // If any events have an `action` field, you should also add logic to handle each action that you are interested in.
  // For example, this code handles the `opened` and `closed` actions for the `issue` event.
  //
  // For more information about the data that you can expect for each event type, see "[AUTOTITLE](/webhooks/webhook-events-and-payloads)."
  if (githubEvent === 'issues') {
    const data = request.body;
    const action = data.action;
    if (action === 'opened') {
      console.log(`An issue was opened with this title: ${data.issue.title}`);
    } else if (action === 'closed') {
      console.log(`An issue was closed by ${data.issue.user.login}`);
    } else {
      console.log(`Unhandled action for the issue event: ${action}`);
    }
  } else if (githubEvent === 'ping') {
    console.log('GitHub sent the ping event');
  } else {
    console.log(`Unhandled event: ${githubEvent}`);
  }
});

// This defines the port where your server should listen.
// 3000 matches the port that you specified for webhook forwarding. For more information, see "[Forward webhooks](#forward-webhooks)."
//
// Once you deploy your code to a server, you should change this to match the port where your server is listening.
const port = 3000;

// This starts the server and tells it to listen at the specified port.
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

Exemplo de JavaScript: testar o código

Para testar seu webhook, você pode usar seu computador ou codespace para atuar como um servidor local. Se tiver problemas com essas etapas, consulte Solução de problemas.

  1. Certifique-se de que esteja encaminhando webhooks. Se não estiver mais encaminhando webhooks, siga as etapas em Encaminhar webhooks novamente.

  2. Em uma janela de terminal separada, execute o seguinte comando para iniciar um servidor local em seu computador ou codespace. Substitua FILE_PATH pelo caminho para o arquivo em que o código da seção anterior está armazenado.

    Shell
    node FILE_NAME
    

    Você deve ver a saída que diz Server is running on port 3000.

  3. Acione seu webhook. Por exemplo, se você criou um webhook de repositório que está inscrito no evento issues, abra um problema em seu repositório. Você também pode reenviar uma entrega anterior de webhook. Para saber mais, confira Entregar webhooks novamente.

  4. Navegue até a URL de proxy de webhook no smee.io. Você deverá ver um evento que corresponde ao evento que acionou ou reenviou. Isso indica que o GitHub enviou com êxito uma entrega de webhook ao URL do conteúdo que você especificou.

  5. Na janela do terminal em que smee --url WEBHOOK_PROXY_URL --path /webhook --port 3000 foi executado, você deverá ver algo como POST http://127.0.0.1:3000/webhook - 202. Isso indica que o smee encaminhou com êxito seu webhook ao servidor local.

  6. Na janela do terminal em que node FILE_NAME foi executado, você deverá ver uma mensagem correspondente ao evento que foi enviado. Por exemplo, se você usar o código de exemplo acima e reenviar o evento ping, deverá ver "GitHub enviou o evento de ping".

  7. Em ambas as janelas de terminal, pressione Ctrl+C para interromper o servidor local e parar de escutar os webhooks encaminhados.

Agora que o código já foi testado localmente, você pode fazer alterações para usar o webhook em produção. Para saber mais, confira as Próximas etapas. Se teve problemas para testar o código, tente as etapas em Solução de problemas.

Solução de problemas

Se não obtiver os resultados esperados descritos nas etapas de teste, tente o seguinte:

  • Certifique-se de que o webhook esteja usando o URL do proxy do webhook (URL do Smee.io). Para obter mais informações sobre o URL do proxy do webhook, confira Obter um URL do proxy do webhook. Para obter mais informações sobre suas configurações de webhook, confira Criar webhooks.
  • Se puder escolher qual tipo de conteúdo usar, certifique-se de que seu webhook use o tipo de conteúdo JSON. Para obter mais informações sobre suas configurações de webhook, confira Criar webhooks.
  • Certifique-se de que o cliente smee e o servidor local estejam em execução. Você terá esses processos em execução em duas janelas de terminal separadas.
  • Certifique-se de que o servidor esteja escutando a mesma porta para a qual o smee.io está encaminhando webhooks. Muitos dos exemplos neste artigo usam a porta 3000.
  • Certifique-se de que o caminho para o qual smee.io esteja encaminhando webhooks corresponda a uma rota definida em seu código. Os exemplos neste artigo usam o caminho /webhooks.
  • Verifique se há mensagens erros nas janelas de terminal em que você está executando o cliente smee e o servidor local.
  • Verifique o GitHub para verificar se uma entrega de webhook foi acionada. Para saber mais, confira Visualizar entregas do webhook.
  • Verifique o URL do proxy do webhook em smee.io. Você deverá ver um evento que corresponde ao evento que acionou ou reenviou. Isso indica que o GitHub enviou com êxito uma entrega de webhook ao URL do conteúdo que você especificou.

Próximas etapas

Este artigo demonstrou como escrever código para lidar com entregas de webhooks. Ele também demonstrou como testar seu código usando seu computador ou codespace como um servidor local e encaminhar entregas de webhooks do GitHub para seu servidor local via smee.io. Quando terminar de testar seu código, talvez você queira modificá-lo e implantá-lo em um servidor.

Modificar o código

Este artigo apresentou exemplos básicos que imprimem uma mensagem quando uma entrega de webhook é recebida. Talvez você queira modificar o código para executar outra ação. Por exemplo, você pode modificar o código para:

  • Fazer uma solicitação à API do GitHub
  • Enviar uma mensagem no Slack
  • Eventos de log
  • Atualizar uma ferramenta externa de gerenciamento de projetos

Verificar se a entrega é proveniente de GitHub

No seu código que lida com entregas de webhook, você deve validar que a entrega é proveniente do GitHub antes de processá-la. Para saber mais, confira Validação de entregas de webhooks.

Implantar seu código em um servidor

Este artigo demonstrou como usar seu computador ou codespace como um servidor enquanto você desenvolve seu código. Quando o código estiver pronto para uso em produção, você deverá implantá-lo em um servidor dedicado.

Ao fazer isso, talvez seja necessário atualizar seu código para refletir o host e a porta em que o servidor está escutando.

Atualizar a URL do webhook

Quando você tiver um servidor configurado para receber tráfego de webhook do GitHub, atualize o URL nas configurações do webhook. Talvez seja necessário atualizar a rota que seu código usa para que ela corresponda à parte do caminho da nova URL. Por exemplo, se a nova URL do webhook for https://example.com/github-webhooks, você deverá alterar a rota nesses exemplos de /webhooks para /github-webhooks.

Você não deve usar o smee.io para encaminhar seus webhooks na produção.

Seguir as práticas recomendadas

Você deve procurar seguir as práticas recomendadas com seus webhooks. Para saber mais, confira Melhores práticas para usar webhooks.

Leitura adicional