# REST API 및 Ruby를 사용하여 스크립팅

Octokit.rb SDK를 사용하여 REST API와 상호 작용하는 스크립트를 작성하는 방법을 알아봅니다.

## Octokit.rb 정보

Ruby를 사용하여 REST API GitHub 와 GitHub 상호 작용하는 스크립트를 작성하려면 Octokit.rb SDK를 사용하는 것이 좋습니다. Octokit.rb는 GitHub에 의해 유지 관리됩니다. SDK는 모범 사례를 구현하고 Ruby를 통해 REST API와 보다 쉽게 상호 작용할 수 있도록 합니다. Octokit.rb는 모든 최신 브라우저, Node.rb 및 Deno에서 작동합니다. Octokit.rb에 대한 자세한 정보는 [Octokit.rb 추가 정보](https://github.com/octokit/octokit.rb/#readme)를 참조하세요.

## 필수 조건

이 가이드에서는 Ruby 및 REST API에 대해 잘 알고 있다고 GitHub 가정합니다. REST API에 대한 자세한 내용은 [REST API 시작](/ko/enterprise-server@3.22/rest/using-the-rest-api/getting-started-with-the-rest-api)을(를) 참조하세요.

Octokit.rb 라이브러리를 사용하려면 `octokit` 젬을 설치하고 가져와야 합니다. 이 가이드에서는 Ruby의 규칙에 따라 import 문을 사용합니다. 다른 설치 방법에 대한 자세한 내용은 [Octokit.rb README의 설치 섹션](https://github.com/octokit/octokit.rb/#installation)을 참조하세요.

## 인스턴스화 및 인증

> \[!WARNING]
> 인증 자격 증명을 암호처럼 처리합니다.
>
> 자격 증명을 안전하게 유지하려면 자격 증명을 비밀로 저장하고 스크립트를 실행할 GitHub Actions수 있습니다. 자세한 내용은 [GitHub Actions에서 비밀 사용](/ko/enterprise-server@3.22/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets)을(를) 참조하세요.

> 이러한 옵션을 사용할 수 경우 다른 CLI 서비스를 사용하여 자격 증명을 안전하게 저장하는 것이 좋습니다.

### personal access token를 사용하여 인증하기

개인 용도로 REST API를 GitHub 사용하려는 경우, personal access token를 만들 수 있습니다. 자세한 내용은 personal access token 만들기에 대해 [개인용 액세스 토큰 관리](/ko/enterprise-server@3.22/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)을 참조하세요.

먼저 `octokit` 라이브러리가 필요합니다. 그런 다음 `Octokit`를 personal access token 옵션으로 전달하여 `access_token`의 인스턴스를 생성합니다. 다음 예제에서 `YOUR-TOKEN`를 사용자의 personal access token(으)로 바꾸세요.

```ruby copy
require 'octokit'

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

### GitHub App를 사용하여 인증하기

조직이나 다른 사용자를 대신하여 API를 사용하려면 GitHub에서 제안하는 GitHub App을 사용하는 것이 좋습니다. 엔드포인트를 사용할 수 있는 GitHub Apps경우 해당 엔드포인트에 대한 REST 참조 설명서에 필요한 토큰 유형 GitHub App 이 표시됩니다. 자세한 내용은 [GitHub 앱 등록](/ko/enterprise-server@3.22/apps/creating-github-apps/registering-a-github-app/registering-a-github-app) 및 [GitHub 앱을 사용한 인증 정보](/ko/enterprise-server@3.22/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app)을(를) 참조하세요.

`octokit`를 요구하는 대신, `Octokit::Client`의 정보를 옵션으로 전달하여 GitHub App의 인스턴스를 생성합니다. 다음 예제에서는 `APP_ID`을(를) 앱의 ID로, `PRIVATE_KEY`을(를) 앱의 프라이빗 키로, 그리고 `INSTALLATION_ID`을(를) 대신 인증하려는 앱 설치의 ID로 바꿉니다. 앱 ID를 찾고 앱의 설정 페이지 설정에서 프라이빗 키를 생성할 수 있습니다. 자세한 내용은 [GitHub 앱에 대한 프라이빗 키 관리](/ko/enterprise-server@3.22/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps)을(를) 참조하세요.
`GET /users/{username}/installation`, `GET /repos/{owner}/{repo}/installation`, `GET /orgs/{org}/installation` 엔드포인트를 사용하여 설치 ID를 가져올 수 있습니다. 자세한 내용은 [GitHub Apps에 대한 REST API 엔드포인트](/ko/enterprise-server@3.22/rest/apps/apps)을 참조하세요. 의 이름으로 `HOSTNAME`바꿉다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)
```

### GitHub Actions에서 인증

워크플로 GitHub Actions 에서 API를 GitHub 사용하려면 토큰을 만드는 대신 기본 제공 `GITHUB_TOKEN` 으로 인증하는 것이 좋습니다.
`GITHUB_TOKEN` 키를 사용하여 `permissions`에 대한 사용 권한을 부여할 수 있습니다.
`GITHUB_TOKEN`에 대한 자세한 내용은 [GITHUB\_TOKEN](/ko/enterprise-server@3.22/actions/concepts/security/github_token)을(를) 참조하세요.

워크플로가 워크플로 리포지토리 외부의 리소스에 액세스해야 하는 경우 `GITHUB_TOKEN`을 사용할 수 없습니다. 이 경우 자격 증명을 비밀로 저장하고 아래 예제의 `GITHUB_TOKEN`을 비밀의 이름으로 바꿉니다. 비밀에 대한 자세한 내용은 [GitHub Actions에서 비밀 사용](/ko/enterprise-server@3.22/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets)을(를) 참조하세요.

키워드를 `run` 사용하여 워크플로에서 GitHub Actions Ruby 스크립트를 실행하는 경우 값을 `GITHUB_TOKEN` 환경 변수로 저장할 수 있습니다. 스크립트는 환경 변수에 `ENV['VARIABLE_NAME']`로 액세스할 수 있습니다.

예를 들어 이 워크플로 단계에서 `GITHUB_TOKEN`이라는 환경 변수에 `TOKEN`을 저장합니다.

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

워크플로가 실행하는 스크립트는 `ENV['TOKEN']`을 인증하는 데 사용합니다.

```ruby copy
require 'octokit'

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

### 인증 없는 인스턴스화

트래픽률 제한이 낮고 일부 엔드포인트를 사용할 수 없어도 인증 없이 REST API를 사용할 수 있습니다. 인증하지 않고 인스턴스 `Octokit`을(를) 만들려면 `access_token` 옵션을 전달하지 마세요.

```ruby copy
require 'octokit'

octokit = Octokit::Client.new
```

## 요청하기

Octokit은 요청을 만드는 여러 가지 방법을 지원합니다. 엔드포인트에 대한 HTTP 동사와 경로를 알고 있는 경우 `request` 메서드를 사용하여 요청을 수행할 수 있습니다. IDE에서 자동 완성 및 입력을 이용하려는 경우 `rest` 메서드를 사용할 수 있습니다. 페이지를 매긴 엔드포인트의 경우 `paginate` 메서드를 사용하여 여러 데이터 페이지를 요청할 수 있습니다.

### `request` 메서드를 사용하여 요청을 수행합니다.

`request` 메서드를 사용하여 요청을 만들려면 HTTP 메서드와 경로를 첫 번째 인수로 전달합니다. 해시의 본문, 쿼리, 경로 매개 변수를 두 번째 인수로 패스합니다. 예를 들어 `GET`에 `/repos/{owner}/{repo}/issues`을 요청하고 `owner`, `repo`, `per_page` 매개변수를 전달하려면 다음을 수행하세요.

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

`request` 메서드는 자동으로 `Accept: application/vnd.github+json` 머리글을 전달합니다. 추가 헤더 또는 다른 `Accept` 헤더를 전달하려면 두 번째 인수로 전달되는 해시에 `headers` 옵션을 추가합니다.
`headers` 옵션의 값은 헤더 이름을 키로, 헤더 값을 값으로 가지고 있는 해시입니다. 예를 들어 `content-type`의 값과 함께 `text/plain` 헤더를 보내려면 다음을 수행합니다.

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

### `rest` 엔드포인트 메서드를 사용하여 요청을 수행하기

모든 REST API 엔드포인트에는 Octokit에 연결된 `rest` 엔드포인트 메서드가 있습니다. 이러한 메서드는 일반적으로 편의를 위해 IDE에서 자동 완성됩니다. 모든 매개 변수를 해시로 메서드에 전달할 수 있습니다.

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

### 페이지 나열된 요청 만들기

엔드포인트가 페이지 단위로 나뉘어 있고 둘 이상의 결과 페이지를 가져오려는 경우 `paginate` 메서드를 사용할 수 있습니다.
`paginate`는 마지막 페이지에 도달할 때까지 결과의 다음 페이지를 가져온 다음 모든 결과를 배열로 반환합니다. 일부 엔드포인트는 페이지네이션된 결과를 배열로 반환하는 대신 객체 내 배열 형태로 반환합니다. 원시 결과가 개체인 경우에도 `paginate`는 항상 항목 배열을 반환합니다.

예를 들어 다음 예제에서는 `github/docs` 리포지토리에서 모든 이슈를 가져옵니다. 한 번에 100개의 이슈를 요청하지만 함수는 데이터의 마지막 페이지에 도달할 때까지 반환되지 않습니다.

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

이 `paginate` 메서드는 결과의 각 페이지를 처리하는 데 사용할 수 있는 선택적 블록을 허용합니다. 이렇게 하면 응답에서 원하는 데이터만 수집할 수 있습니다. 예를 들어 다음 예제에서는 제목에 "test"가 포함된 이슈가 반환될 때까지 결과를 계속 가져옵니다. 반환된 데이터 페이지의 경우 이슈 제목과 작성자만 저장됩니다.

```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
```

모든 결과를 한 번에 가져오는 대신 한 번에 단일 페이지를 반복하는 데 `octokit.paginate.iterator()`를 사용할 수 있습니다. 예를 들어 다음 예제에서는 결과의 한 페이지를 한 번에 가져오고 다음 페이지를 가져오기 전에 페이지에서 각 개체를 처리합니다. 제목에 "test"가 포함된 이슈에 도달하면 스크립트는 반복을 중지하고 처리된 각 개체의 이슈 제목 및 이슈 작성자를 반환합니다. 반복기는 페이지를 매긴 데이터를 가져오기 위한 가장 메모리 효율적인 메서드입니다.

```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
```

`paginate` 엔드포인트 메서드에서도 `rest` 메서드를 사용할 수 있습니다.
`rest` 엔드포인트 메서드를 첫 번째 인수로 전달하고 매개 변수를 두 번째 인수로 전달합니다.

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

페이지 매김에 대한 자세한 내용은 [REST API에서 페이지 매김 사용](/ko/enterprise-server@3.22/rest/using-the-rest-api/using-pagination-in-the-rest-api)을(를) 참조하세요.

## 오류 포착하기

### 모든 오류 포착하기

경우에 따라 REST API에서 GitHub 오류를 반환합니다. 예를 들어 액세스 토큰이 만료되었거나 필수 매개 변수를 생략하면 오류가 발생합니다. Octokit.rb는 `400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `404 Not Found`및 `422 Unprocessable Entity` 이외의 오류가 발생하면 요청을 자동으로 다시 시도합니다. 재시도 후에도 API 오류가 발생하면 Octokit.rb는 응답(`response.status`) 및 응답 헤더(`response.headers`)의 HTTP 상태 코드를 포함하는 오류를 throw합니다. 코드에서 이러한 오류를 처리해야 합니다. 예를 들어 try/catch 블록을 사용하여 오류를 포착할 수 있습니다.

```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
```

### 의도한 오류 코드 처리하기

경우에 따라 GitHub 4xx 상태 코드를 사용하여 오류가 아닌 응답을 나타냅니다. 사용 중인 엔드포인트에서 이 작업을 수행하는 경우, 특정 오류에 대한 처리를 추가할 수 있습니다. 예를 들어 `GET /user/starred/{owner}/{repo}` 엔드포인트는 리포지토리에 별표를 하지 않은 경우 `404`를 반환합니다. 다음 예제에서는 `404` 응답을 사용하여 리포지토리가 별표 표시되지 않았음을 나타내고 다른 모든 오류 코드는 오류로 처리됩니다.

```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
```

### 트래픽률 제한 오류 처리

트래픽률 제한 오류가 표시되는 경우 대기 후 요청을 다시 시도할 수 있습니다. 요청 한도에 도달하면 GitHub는 `403 Forbidden` 오류로 응답하며, `x-ratelimit-remaining` 응답 헤더 값은 `"0"`가 됩니다. 응답 헤더에는 현재 트래픽률 제한 창이 재설정되는 시간을 UTC Epoch 초 단위로 알려주는 `x-ratelimit-reset` 헤더가 포함됩니다.
`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)
```

## 응답 사용

`request` 메서드는 요청이 성공한 경우 응답 개체를 반환합니다. 응답 개체는 `data`(엔드포인트에서 반환된 응답 본문), `status`(HTTP 응답 코드), `url`(요청의 URL) 및 `headers`(응답 머리글을 포함하는 해시)입니다. 달리 지정하지 않는 한 응답 본문은 JSON 형식입니다. 일부 엔드포인트는 응답 본문을 반환하지 않습니다. 이 경우 `data` 속성은 생략됩니다.

```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']}"
```

마찬가지로, `paginate` 메서드는 응답 개체를 반환합니다.
`request`이(가) 성공한 경우, `response` 개체에는 데이터, 상태, URL 및 헤더가 포함됩니다.

```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']}"
```

## 예제 스크립트

다음은 Octokit.rb를 사용하는 전체 예제 스크립트입니다. 스크립트는 `Octokit`를 가져오고 새 인스턴스 `Octokit`를 만듭니다.
GitHub App 대신 personal access token로 인증하려면 `App` 대신 `Octokit`를 가져와 인스턴스화하면 됩니다. 자세한 내용은 이 가이드의 [GitHub App를 사용한 인증](#authenticating-with-a-github-app)을 참조하세요.

`get_changed_files` 함수는 끌어오기 요청에 대해 변경된 모든 파일을 가져옵니다.
`comment_if_data_files_changed` 함수는 `get_changed_files` 함수를 호출합니다. 끌어오기 요청이 변경된 파일이 파일 경로에 `/data/`가 포함된 경우 함수는 끌어오기 요청에 대해 설명을 달게 됩니다.

```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]
> 이는 단지 기본적인 예제일 뿐입니다. 실제로 오류 처리 및 조건부 검사를 사용하여 다양한 시나리오를 처리할 수 있습니다.

## 다음 단계

GitHub REST API 및 Octokit.rb 사용 방법에 대해 자세히 알아보려면 다음 리소스를 살펴보세요.

* Octokit.rb에 대한 자세한 내용은 [Octokit.rb 설명서](https://github.com/octokit/octokit.rb/#readme)를 참조하세요.
* 요청 및 응답 구조를 포함하여 사용 가능한 REST API 엔드포인트에 대한 GitHub자세한 내용은 [GITHUB REST API 설명서](/ko/enterprise-server@3.22/rest)을 참조하세요.