# Scripts com a API REST e o Ruby

Saiba como escrever um script usando o SDK do Octokit.rb para interagir com a API REST.

## Sobre o Octokit.rb

Se você quiser escrever um script usando Ruby para interagir com a GitHub API REST, GitHub recomenda que você use o SDK octokit.rb. Octokit.rb é mantido por GitHub. O SDK implementa as melhores práticas e facilita a interação com a API REST por meio do Ruby. O Octokit.rb funciona com todos os navegadores modernos, Node.rb e Deno. Para obter mais informações sobre o Octokit.rb, confira o arquivo [LEIAME do Octokit.rb](https://github.com/octokit/octokit.rb/#readme).

## Pré-requisitos

Este guia pressupõe que você esteja familiarizado com o Ruby e a GitHub API REST. Para obter informações sobre a API REST, confira [Introdução à API REST](/pt/enterprise-server@3.22/rest/using-the-rest-api/getting-started-with-the-rest-api).

Você deve instalar e importar o gem `octokit` para usar a biblioteca Octokit.rb. Este guia usa instruções de importação de acordo com as convenções do Ruby. Para obter mais informações sobre os diferentes métodos de instalação, consulte a [seção Instalação do LEIAME do Octokit.rb](https://github.com/octokit/octokit.rb/#installation).

## Instanciação e autenticação

> \[!WARNING]
> Trate suas credenciais de autenticação como uma senha.
>
> Para manter suas credenciais seguras, você pode armazenar suas credenciais como segredo e executar seu script por meio de GitHub Actions. Para saber mais, confira [Usar segredos em ações do GitHub](/pt/enterprise-server@3.22/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets).

> Se , considere usar outro serviço da CLI para armazenar suas credenciais com segurança.

### Autenticando com um personal access token

Se você quiser usar a GitHub API REST para uso pessoal, poderá criar uma personal access token. Para obter mais informações sobre como criar um personal access token, consulte [Gerenciar seus tokens de acesso pessoal](/pt/enterprise-server@3.22/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).

Primeiro, exija a biblioteca `octokit`. Em seguida, crie uma instância de `Octokit` passando sua personal access token como a opção `access_token`. No exemplo a seguir, substitua `YOUR-TOKEN` por sua personal access token.

```ruby copy
require 'octokit'

octokit = Octokit::Client.new(access_token: 'YOUR-TOKEN')
```

### Autenticando com um GitHub App

Se você quiser usar a API em nome de uma organização ou de outro usuário, GitHub recomenda que você use uma GitHub App. Se um endpoint estiver disponível para GitHub Apps, a documentação de referência da REST API para esse endpoint indicará que tipo de token GitHub App é necessário. Para saber mais, confira [Registrando um aplicativo GitHub](/pt/enterprise-server@3.22/apps/creating-github-apps/registering-a-github-app/registering-a-github-app) e [Sobre a autenticação com um aplicativo GitHub](/pt/enterprise-server@3.22/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app).

Em vez de exigir `octokit`, crie uma instância de `Octokit::Client` passando as informações da sua GitHub App como opções. No exemplo a seguir, substitua `APP_ID` pelo ID do seu aplicativo, `PRIVATE_KEY` pela chave privada do seu aplicativo e `INSTALLATION_ID` pelo ID da instalação do seu aplicativo em nome do qual você deseja autenticar. Você pode encontrar a ID do seu aplicativo e gerar uma chave privada na página de configurações do aplicativo. Para saber mais, confira [Gerenciando chaves privadas para aplicativos GitHub](/pt/enterprise-server@3.22/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps). Você pode obter uma ID de instalação com os pontos de extremidade `GET /users/{username}/installation`, `GET /repos/{owner}/{repo}/installation` ou `GET /orgs/{org}/installation`. Para obter mais informações, consulte [Pontos de extremidade da API REST para o GitHub Apps](/pt/enterprise-server@3.22/rest/apps/apps). Substitua `HOSTNAME` pelo nome de sua instância do GitHub Enterprise Server.

```ruby copy
require 'octokit'

app = Octokit::Client.new(
  client_id: APP_ID,
  client_secret: PRIVATE_KEY,
  installation_id: INSTALLATION_ID
)

octokit = Octokit::Client.new(bearer_token: app.create_app_installation.access_token)
```

### Autenticação em GitHub Actions

Se você deseja usar a API em um GitHub Actions fluxo de trabalho, GitHub recomenda-se que você se autentique com o token integrado `GITHUB_TOKEN` em vez de criar um token. Você pode conceder permissões à `GITHUB_TOKEN` com a chave `permissions`. Para obter mais informações sobre `GITHUB_TOKEN`, confira [GITHUB\_TOKEN](/pt/enterprise-server@3.22/actions/concepts/security/github_token).

Se o fluxo de trabalho precisar acessar recursos fora do repositório dele, então você não poderá usar `GITHUB_TOKEN`. Nesse caso, armazene suas credenciais como um segredo e substitua `GITHUB_TOKEN` nos exemplos abaixo pelo nome do segredo. Para saber mais sobre segredos, confira [Usar segredos em ações do GitHub](/pt/enterprise-server@3.22/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets).

Se você usar a palavra-chave `run` para executar seu script Ruby em seus fluxos de trabalho GitHub Actions, poderá armazenar o valor de `GITHUB_TOKEN` como uma variável de ambiente. Seu script pode acessar a variável de ambiente como `ENV['VARIABLE_NAME']`.

Por exemplo, essa etapa do fluxo de trabalho armazena `GITHUB_TOKEN` em uma variável de ambiente chamada `TOKEN`:

```yaml
- name: Run script
  env:
    TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    ruby .github/actions-scripts/use-the-api.rb
```

O script que o fluxo de trabalho executa usa `ENV['TOKEN']` para se autenticar:

```ruby copy
require 'octokit'

octokit = Octokit::Client.new(access_token: ENV['TOKEN'])
```

### Instanciação sem autenticação

Você pode usar a API REST sem autenticação, embora isso resulte em uma limitação de taxa mais baixa e não permita o uso de alguns endpoints. Para criar uma instância de `Octokit` sem autenticação, não passe a opção `access_token`.

```ruby copy
require 'octokit'

octokit = Octokit::Client.new
```

## Como fazer solicitações

O Octokit dá suporte a várias maneiras de fazer solicitações. Você pode usar o método `request` para fazer solicitações se souber o verbo HTTP e o caminho para o ponto de extremidade. Você pode usar o método `rest` se quiser aproveitar o preenchimento automático em seu IDE e digitar. Para pontos de extremidade paginados, você pode usar o método `paginate` para solicitar várias páginas de dados.

### Como usar o método `request` para fazer solicitações

Para usar o método `request` a fim de fazer solicitações, passe o método HTTP e o caminho como o primeiro argumento. Passe qualquer parâmetro de corpo, consulta ou caminho em um hash como o segundo argumento. Por exemplo, para fazer uma solicitação `GET` para `/repos/{owner}/{repo}/issues` e passar os parâmetros `owner`, `repo` e `per_page`:

```ruby copy
octokit.request("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 2)
```

O método `request` passa automaticamente o cabeçalho `Accept: application/vnd.github+json`. Para passar cabeçalhos adicionais ou um cabeçalho `Accept` diferente, adicione uma opção `headers` ao hash que é passado como um segundo argumento. O valor da opção `headers` é um hash com os nomes de cabeçalho como chaves e os valores de cabeçalho como valores. Por exemplo, para enviar um cabeçalho `content-type` com o valor `text/plain`:

```ruby copy
octokit.request("POST /markdown/raw", text: "Hello **world**", headers: { "content-type" => "text/plain" })
```

### Como usar métodos endpoint `rest` para fazer solicitações

Cada ponto de extremidade da API REST tem um método de ponto de extremidade `rest` associado no Octokit. Esses métodos geralmente são preenchidos automaticamente em seu IDE para conveniência. Você pode passar qualquer parâmetro como um hash para o método.

```ruby copy
octokit.rest.issues.list_for_repo(owner: "github", repo: "docs", per_page: 2)
```

### Como fazer solicitações paginadas

Se o endpoint for paginado e você quiser recuperar mais de uma página de resultados, poderá usar o método `paginate`.
`paginate` buscará a próxima página de resultados até chegar à última página e retornará todos os resultados como uma matriz. Alguns pontos de extremidade retornam resultados paginados como matriz em um objeto, em vez de retornar os resultados paginados como uma matriz.
`paginate` sempre retorna uma matriz de itens, mesmo que o resultado bruto tenha sido um objeto .

Por exemplo, o exemplo a seguir obtém todos os problemas do repositório `github/docs`. Embora solicite 100 solicitações por vez, a função não retornará até que a última página de dados seja atingida.

```ruby copy
issue_data = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)
```

O método `paginate` aceita um bloco opcional, que você pode usar para processar cada página de resultados. Isso permite coletar apenas os dados desejados da resposta. Por exemplo, o exemplo a seguir continua buscando resultados até que seja retornada uma questão que inclua "teste" no título. Para as páginas de dados que foram retornadas, apenas o título e o autor da questão são armazenados.

```ruby copy
issue_data = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100) do |response, done|
  response.data.map do |issue|
    if issue.title.include?("test")
      done.call
    end
    { title: issue.title, author: issue.user.login }
  end
end
```

Em vez de buscar todos os resultados de uma só vez, você pode usar `octokit.paginate.iterator()` para percorrer uma só página de cada vez. Por exemplo, o caso a seguir busca uma página de resultados por vez e processa cada objeto da página atual antes de buscar a próxima. Uma vez encontrado um problema com "teste" no título, o script interrompe a iteração e retorna o título e o autor do problema de cada objeto que foi processado. O iterador é o método mais eficiente em termos de memória para buscar dados paginados.

```ruby copy
iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)
issue_data = []
break_loop = false
iterator.each do |data|
  break if break_loop
  data.each do |issue|
    if issue.title.include?("test")
      break_loop = true
      break
    else
      issue_data << { title: issue.title, author: issue.user.login }
    end
  end
end
```

Você também pode usar o método `paginate` com os métodos de endpoint `rest`. Passe o método de ponto de extremidade `rest` como o primeiro argumento e quaisquer parâmetros como o segundo argumento.

```ruby copy
iterator = octokit.paginate.iterator(octokit.rest.issues.list_for_repo, owner: "github", repo: "docs", per_page: 100)
```

Para saber mais sobre a paginação, confira [Como usar paginação na API REST](/pt/enterprise-server@3.22/rest/using-the-rest-api/using-pagination-in-the-rest-api).

## Captura de erros

### Capturando todos os erros

Às vezes, a GitHub API REST retornará um erro. Por exemplo, um erro será exibido se o token de acesso tiver expirado ou se um parâmetro obrigatório for omitido. O Octokit.rb faz automaticamente novas tentativas de executar a solicitação quando obtém um erro diferente de `400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `404 Not Found` ou `422 Unprocessable Entity`. Se ocorrer um erro de API mesmo após novas tentativas, o Octokit.rb gera um erro que inclui o código de status HTTP da resposta (`response.status`) e os cabeçalhos da resposta (`response.headers`). Você deve tratar esses erros em seu código. Por exemplo, você pode usar um bloco try/catch para capturar erros:

```ruby copy
begin
files_changed = []

iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", owner: "github", repo: "docs", pull_number: 22809, per_page: 100)
iterator.each do | data |
    files_changed.concat(data.map {
      | file_data | file_data.filename
    })
  end
rescue Octokit::Error => error
if error.response
puts "Error! Status: #{error.response.status}. Message: #{error.response.data.message}"
end
puts error
end
```

### Tratamento de códigos de erro previstos

Às vezes, GitHub usa um código de status 4xx para indicar uma resposta sem erro. Se o endpoint que você está usando fizer isso, você poderá adicionar tratamento adicional para erros específicos. Por exemplo, o endpoint `GET /user/starred/{owner}/{repo}` retornará `404` se o repositório não estiver marcado com estrela. O exemplo a seguir usa a resposta `404` para indicar que o repositório não foi estrelado; todos os demais códigos de erros são tratados como erros.

```ruby copy
begin
octokit.request("GET /user/starred/{owner}/{repo}", owner: "github", repo: "docs")
puts "The repository is starred by me"
rescue Octokit::NotFound => error
puts "The repository is not starred by me"
rescue Octokit::Error => error
puts "An error occurred while checking if the repository is starred: #{error&.response&.data&.message}"
end
```

### Tratamento de erros de limite de taxa

Se você receber um erro de limite de taxa, talvez seja necessário repetir a solicitação após aguardar um tempo. Quando houver limitação de taxa, GitHub retornará um erro `403 Forbidden`, e o valor do cabeçalho de resposta `x-ratelimit-remaining` será `"0"`. Os cabeçalhos de resposta incluirão um cabeçalho `x-ratelimit-reset`, que informa a hora em que a janela de limite de taxa atual é redefinida, em segundos UTC. Você pode repetir a solicitação após aguardar o tempo especificado por `x-ratelimit-reset`.

```ruby copy
def request_retry(route, parameters)
 begin
 response = octokit.request(route, parameters)
 return response
 rescue Octokit::RateLimitExceeded => error
 reset_time_epoch_seconds = error.response.headers['x-ratelimit-reset'].to_i
 current_time_epoch_seconds = Time.now.to_i
 seconds_to_wait = reset_time_epoch_seconds - current_time_epoch_seconds
 puts "You have exceeded your rate limit. Retrying in #{seconds_to_wait} seconds."
 sleep(seconds_to_wait)
 retry
 rescue Octokit::Error => error
 puts error
 end
 end

 response = request_retry("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 2)
```

## Como usar a resposta

O método `request` retornará um objeto de resposta se a solicitação tiver sido bem-sucedida. O objeto de resposta contém `data` (o corpo da resposta retornado pelo ponto de extremidade), `status` (o código de resposta HTTP), `url` (a URL da solicitação) e `headers` (um hash que contém os cabeçalhos da resposta). A menos que especificado de outra forma, o corpo da resposta está no formato JSON. Alguns endpoints não retornam um corpo de resposta; nesses casos, a propriedade `data` é omitida.

```ruby copy
response = octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}", owner: "github", repo: "docs", issue_number: 11901)
 puts "The status of the response is: #{response.status}"
 puts "The request URL was: #{response.url}"
 puts "The x-ratelimit-remaining response header is: #{response.headers['x-ratelimit-remaining']}"
 puts "The issue title is: #{response.data['title']}"
```

Da mesma forma, o método `paginate` retorna um objeto de resposta. Se o `request` for bem-sucedido, o objeto `response` conterá dados, status, URL e cabeçalhos.

```ruby copy
response = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)
puts "#{response.data.length} issues were returned"
puts "The title of the first issue is: #{response.data[0]['title']}"
```

## Script de exemplo

Aqui está um script de exemplo completo que usa o Octokit.rb. O script importa `Octokit` e cria uma instância de `Octokit`. Se você quiser autenticar com um GitHub App em vez de um personal access token, você importaria e instanciaria `App` em vez de `Octokit`. Para saber mais, confira [Autenticação com um GitHub App](#authenticating-with-a-github-app) neste guia.

A função `get_changed_files` obtém todos os arquivos alterados para uma solicitação de pull. A função `comment_if_data_files_changed` chama a função `get_changed_files`. Se qualquer um dos arquivos que a solicitação de pull alterou incluir `/data/` no caminho, a função comentará sobre a solicitação de pull.

```ruby copy
require "octokit"

 octokit = Octokit::Client.new(access_token: "YOUR-TOKEN")

 def get_changed_files(octokit, owner, repo, pull_number)
 files_changed = []

 begin
 iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", owner: owner, repo: repo, pull_number: pull_number, per_page: 100)
 iterator.each do | data |
     files_changed.concat(data.map {
       | file_data | file_data.filename
     })
   end
 rescue Octokit::Error => error
 if error.response
 puts "Error! Status: #{error.response.status}. Message: #{error.response.data.message}"
 end
 puts error
 end

 files_changed
 end

 def comment_if_data_files_changed(octokit, owner, repo, pull_number)
 changed_files = get_changed_files(octokit, owner, repo, pull_number)

 if changed_files.any ? {
   | file_name | /\/data\//i.match ? (file_name)
 }
 begin
 comment = octokit.create_pull_request_review_comment(owner, repo, pull_number, "It looks like you changed a data file. These files are auto-generated. \n\nYou must revert any changes to data files before your pull request will be reviewed.")
 comment.html_url
 rescue Octokit::Error => error
 if error.response
 puts "Error! Status: #{error.response.status}. Message: #{error.response.data.message}"
 end
 puts error
 end
 end
 end

# Example usage
owner = "github"
repo = "docs"
pull_number = 22809
comment_url = comment_if_data_files_changed(octokit, owner, repo, pull_number)

puts "A comment was added to the pull request: #{comment_url}"
```

> \[!NOTE]
> Este é apenas um exemplo básico. Na prática, talvez você queira usar tratamento de erros e verificações condicionais para lidar com vários cenários.

## Próximas etapas

Para saber mais sobre como trabalhar com a GitHub API REST e o Octokit.rb, explore os seguintes recursos:

* Para saber mais sobre o Octokit.js, confira a [documentação do Octokit.rb](https://github.com/octokit/octokit.rb/#readme).
* Para obter informações detalhadas sobre os endpoints disponíveis da API REST de GitHub, incluindo as estruturas de solicitação e resposta, consulte o [documentação da API REST GitHub](/pt/enterprise-server@3.22/rest).