# GraphQL을 사용하여 통화 구성

GraphQL API에 인증하는 방법을 알아본 다음 쿼리 및 변형을 만들고 실행하는 방법을 알아봅니다.

## GraphQL을 사용하여 인증

personal access token, GitHub App 또는 OAuth app를 사용하여 GraphQL API에 인증할 수 있습니다.

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

personal access token로 인증하려면 [개인용 액세스 토큰 관리](/ko/enterprise-server@3.22/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)의 단계를 따르세요. 요청하는 데이터는 필요한 범위 또는 권한을 지정합니다.

예를 들어, 토큰이 접근할 수 있는 리포지토리의 모든 이슈를 읽으려면 "issues:read" 권한을 선택하십시오.

모든 fine-grained personal access token항목에는 공용 리포지토리에 대한 읽기 권한이 포함됩니다.
personal access token (classic)를 사용해 공용 리포지토리에 액세스하려면 "public\_repo" 범위를 선택합니다.

토큰에 리소스를 access 데 필요한 범위 또는 권한이 없는 경우 API는 토큰에 필요한 범위 또는 사용 권한을 나타내는 오류 메시지를 반환합니다.

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

조직이나 다른 사용자를 대신하여 API를 사용하려면 GitHub에서 제안하는 GitHub App을 사용하는 것이 좋습니다. 앱의 활동을 추적하려면 앱 설치로 인증하도록 앱을 구성할 수 있습니다. 앱에 대한 활동을 사용자에게 특성화하기 위해 사용자를 대신하여 앱을 인증할 수 있습니다. 두 경우 모두 GraphQL API에 인증하는 데 사용할 수 있는 토큰을 생성합니다. 자세한 내용은 [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) 참조하세요.

### OAuth app를 사용하여 인증하기

OAuth app의 OAuth 토큰으로 인증하려면 먼저 웹 애플리케이션 흐름이나 디바이스 흐름을 사용하여 OAuth app에 권한을 부여해야 합니다. 그런 다음 받은 access 토큰을 사용하여 API를 access 수 있습니다. 자세한 내용은 [OAuth 앱 만들기](/ko/enterprise-server@3.22/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) 및 [OAuth 앱 권한 부여](/ko/enterprise-server@3.22/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps) 참조하세요.

## GraphQL 엔드포인트

REST API에는 수많은 엔드포인트가 있습니다. GraphQL API를 사용하면, 어떤 작업을 수행하든 엔드포인트는 일정하게 유지됩니다. 의 경우 GitHub Enterprise Server해당 엔드포인트는 다음과 같습니다.

<pre>http(s)://HOSTNAME/api/graphql</pre>

## GraphQL과 통신

GraphQL 작업은 여러 줄 JSON으로 구성되므로 GitHub [GraphQL 클라이언트](/ko/enterprise-server@3.22/graphql/guides/using-graphql-clients)를 사용하여 GraphQL을 호출하는 것이 좋습니다.
`curl` 또는 다른 HTTP 말하기 라이브러리를 사용할 수도 있습니다.

REST에서 [HTTP 동사](/ko/enterprise-server@3.22/rest#http-verbs)는 수행되는 작업을 결정합니다. GraphQL에서는 쿼리를 수행하든 변형을 수행하든 관계없이 JSON으로 인코딩된 본문을 제공하므로, HTTP 동사는 `POST`입니다. 엔드포인트에 대한 간단한 [](/ko/enterprise-server@3.22/graphql/guides/introduction-to-graphql#discovering-the-graphql-api)인 `GET`는 예외입니다. GraphQL 및 REST에 대한 자세한 내용은 [REST에서 GraphQL로 마이그레이션](/ko/enterprise-server@3.22/graphql/guides/migrating-from-rest-to-graphql) 참조하세요.

`curl` 명령에서 GraphQL을 쿼리하려면 JSON 페이로드로 `POST` 요청을 수행합니다. 페이로드에는 `query`라는 문자열이 포함되어야 합니다.

```shell
curl -H "Authorization: bearer TOKEN" -X POST -d " \
 { \
   \"query\": \"query { viewer { login }}\" \
 } \
" http(s)://HOSTNAME/api/graphql
```

> \[!NOTE]
> `"query"` 의 문자열 값에 포함된 줄 바꿈 문자는 반드시 이스케이프 처리를 해야 하며, 이를 누락할 경우 스키마 해석 과정에서 구문 오류가 발생할 수 있습니다. `POST` 본문의 경우 외부 큰따옴표와 이스케이프된 내부 큰따옴표를 사용합니다.

### 쿼리 및 변형 작업 정보

GitHub GraphQL API에서 허용되는 두 가지 작업은 *queries* 및 \_mutations\_입니다. GraphQL과 REST를 비교하면 쿼리는 `GET` 요청처럼 작동하고 변형은 `POST`/`PATCH`/`DELETE`처럼 작동합니다. 변형 이름은 어떤 수정이 실행되는지 결정합니다.

속도 제한 규칙에 대한 자세한 내용은 [GraphQL API에 대한 속도 제한 및 쿼리 제한](/ko/enterprise-server@3.22/graphql/overview/rate-limits-and-query-limits-for-the-graphql-api)을(를) 참조하세요.

쿼리 및 변경은 몇 가지 중요한 차이점이 있지만 비슷한 형식을 공유합니다.

### 쿼리 정보

GraphQL 쿼리는 지정한 데이터만 반환합니다. 쿼리를 구성하려면 스칼라만 반환할 때까지 [필드 내의 필드](/ko/enterprise-server@3.22/graphql/guides/introduction-to-graphql#field) ( \_중첩 하위 필드\_라고도 함)를 지정해야 합니다.

쿼리는 다음과 같이 구성됩니다.

<pre>query {
  JSON-OBJECT-TO-RETURN
}</pre>

실제 예제는 [예제 쿼리](#example-query)를 참조하세요.

### 변형 정보

변형을 형성하려면 다음 세 가지를 지정해야 합니다.

1. *변형 이름*. 수행하려는 수정의 유형입니다.
2. *입력 개체*.
   \_입력 필드\_로 구성된, 서버로 보내려는 데이터입니다. 이것을 변형 이름에 인수로서 전달합니다.
3. *페이로드 개체*.
   \_반환 필드\_로 구성된, 서버로부터 반환하려는 데이터입니다. 이것을 변형 이름의 본문으로서 전달합니다.

변형은 다음과 같이 구성됩니다.

<pre>mutation {
  MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) {
    MUTATION-NAME-PAYLOAD
  }
}</pre>

이 예제에서 입력 객체는 `MutationNameInput`, 페이로드 객체는 `MutationNamePayload`입니다.

뮤테이션 참조에 나열된 \_입력 필드\_는 입력 객체로 전달하는 필드입니다. 나열된 \_반환 필드\_는 페이로드 개체로서 전달하는 것입니다.

실제 예제는 [예제 변형](#example-mutation)을 참조하세요.

## 변수 사용

[변수](https://graphql.org/learn/queries/#variables)는 쿼리를 더욱 동적이고 강력하게 만들 수 있으며 변형 입력 개체를 전달할 때 복잡성을 줄일 수 있습니다.

다음은 단일 변수를 사용하는 예제 쿼리입니다.

```graphql
query($number_of_repos:Int!) {
  viewer {
    name
     repositories(last: $number_of_repos) {
       nodes {
         name
       }
     }
   }
}
variables {
   "number_of_repos": 3
}
```

변수를 사용하는 세 단계가 있습니다.

1. `variables` 개체에서 작업 외부의 변수를 정의합니다.

   ```graphql
   variables {
      "number_of_repos": 3
   }
   ```

   개체는 유효한 JSON이어야 합니다. 이 예제에서는 간단한 `Int` 변수 형식을 보여 주지만, 입력 개체와 같은 더 복잡한 변수 형식을 정의할 수 있습니다. 여기에서 여러 변수를 정의할 수도 있습니다.

2. 변수를 인수로서 작업에 전달합니다.

   ```graphql
   query($number_of_repos:Int!){
   ```

   인수는 키-값 쌍이며, 여기서 키는 \_\_ 로 시작하는 `$`(예: `$number_of_repos`)이고 값은 *형식*(예: `Int`)입니다. 형식이 필요한지 여부를 나타내는 `!`를 추가합니다. 여러 변수를 정의한 경우 여기에 여러 인수로서 포함합니다.

3. 작업 내에서 변수를 사용합니다.

   ```graphql
   repositories(last: $number_of_repos) {
   ```

   이 예제에서는 변수를 검색할 리포지토리의 수로 대체합니다. GraphQL은 강력한 입력을 적용하기 때문에 2단계에서 형식을 지정합니다.

이 프로세스는 쿼리 인수를 동적으로 만듭니다. 이제 단순히 `variables` 개체의 값을 변경하고 쿼리의 나머지를 동일하게 유지할 수 있습니다.

변수를 인수로서 사용하면 쿼리를 변경하지 않고도 `variables` 개체의 값을 동적으로 업데이트할 수 있습니다.

## 예제 쿼리

좀 더 복잡한 쿼리를 살펴보고 이 정보를 컨텍스트에 배치해 보겠습니다.

다음 쿼리는 `octocat/Hello-World` 리포지토리를 조회하고, 가장 최근에 종료된 20개의 이슈를 찾고, 각 이슈의 제목, URL, 처음 5개 레이블을 반환합니다.

```graphql
query {
  repository(owner:"octocat", name:"Hello-World") {
    issues(last:20, states:CLOSED) {
      edges {
        node {
          title
          url
          labels(first:5) {
            edges {
              node {
                name
              }
            }
          }
        }
      }
    }
  }
}
```

컴퍼지션을 한 줄씩 살펴보기:

* `query {`

  서버의 데이터를 수정하는 것이 아니라 데이터를 읽고자 하므로, `query`는 루트 작업입니다. 작업을 지정하지 않으면 `query`가 기본값이기도 합니다.

* `repository(owner:"octocat", name:"Hello-World") {`

  쿼리를 시작하기 위해 [`repository`](/ko/enterprise-server@3.22/graphql/reference/repos#object-repository) 개체를 찾으려고 합니다. 스키마 유효성 검사에 따르면 이 개체에 `owner` 및 `name` 인수가 필요합니다.

* `issues(last:20, states:CLOSED) {`

  리포지토리의 모든 이슈를 설명하기 위해 `issues` 개체를 호출합니다.
  \_
  \_에서 단일 `issue`를 쿼리할 수 있지만, 그렇게 할 경우 반환하려는 이슈의 번호를 알아야 하고 이를 인수로서 제공해야 합니다.`repository`

`issues` 개체에 대한 몇 가지 세부 정보:

* [문서](/ko/enterprise-server@3.22/graphql/reference/repos#object-repository)에 따르면 이 개체의 형식은 `IssueConnection`입니다.

* 스키마 유효성 검사에 따르면 이 개체에는 결과의 `last` 또는 `first` 숫자가 인수로서 필요합니다. 이 예제에서는 `20`을 사용합니다.

* 또한 [문서](/ko/enterprise-server@3.22/graphql/reference/repos#object-repository)에 따르면 이 개체는 `states` 열거형의 `IssueState` 인수를 허용하며, 이 열거형은 [](/ko/enterprise-server@3.22/graphql/reference/issues#enum-issuestate) 또는 `OPEN` 값을 수용합니다. 종료된 이슈만 찾으려면 `states` 키에 `CLOSED` 값을 제공합니다.

* `edges {`

`issues` 형식을 가지고 있으므로 `IssueConnection`가 연결임을 알고 있습니다. 개별 문제에 대한 데이터를 검색하려면 `edges` 통해 노드를 access 합니다.

* `node {`

  여기서는 에지 끝에서 노드를 검색합니다.
  [
  `IssueConnection` 문서](/ko/enterprise-server@3.22/graphql/reference/issues#object-issueconnection)에 따르면 `IssueConnection` 형식 끝에 있는 노드는 `Issue` 개체입니다.

* 이제 `Issue` 개체를 검색하고 있다는 것을 알게 되었으므로 [문서](/ko/enterprise-server@3.22/graphql/reference/issues#object-issue)를 살펴보고 반환할 필드를 지정할 수 있습니다.

  ```graphql
  title
  url
  labels(first:5) {
    edges {
      node {
        name
      }
    }
  }
  ```

  여기서 `title` 개체의 `url`, `labels`, `Issue` 필드를 지정합니다.

`labels` 필드의 형식은 [`LabelConnection`](/ko/enterprise-server@3.22/graphql/reference/issues#object-labelconnection)입니다.
`issues` 개체와 마찬가지로 `labels`도 연결이므로 해당 에지를 연결된 노드인 `label` 개체로 이동해야 합니다. 노드에서, 반환하려는 `label` 개체 필드(이 경우 `name`)를 지정할 수 있습니다.

Octocat의 퍼블릭 `Hello-World` 리포지토리에서 이 쿼리를 실행하면 많은 레이블이 반환되지 않습니다. 레이블을 사용하는 자체 리포지토리 중 하나에서 실행해 보면 차이를 확인할 수 있을 것입니다.

## 예제 변형

변형에는 쿼리를 먼저 수행해야만 알 수 있는 정보가 필요한 경우가 많습니다. 이 예제에서는 두 개의 작업을 보여 줍니다.

1. 이슈 ID를 가져오기 위한 쿼리.
2. 이슈에 이모지 반응을 추가하기 위한 변형.

```graphql
query FindIssueID {
  repository(owner:"octocat", name:"Hello-World") {
    issue(number:349) {
      id
    }
  }
}

mutation AddReactionToIssue {
  addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
    reaction {
      content
    }
    subject {
      id
    }
  }
}
```

예제를 하나 살펴보겠습니다. 간단한 작업처럼 보입니다. 이슈에 이모지 반응을 추가합니다.

그렇다면 쿼리로 시작해야 하는지 어떻게 알 수 있을까요? 아직 하지 않았습니다.

서버의 데이터를 수정하려고 하므로(이슈에 이모지 연결) 유용한 변형을 찾기 위해 스키마를 검색하는 것으로 시작합니다. 참조 문서는 다음 설명과 함께 [`addReaction`](/ko/enterprise-server@3.22/graphql/reference/reactions#mutation-addreaction) 변형을 보여 줍니다. `Adds a reaction to a subject.` 완벽합니다!

변형에 대한 문서에는 세 개의 입력 필드가 나열됩니다.

* `clientMutationId`(`String`)
* `subjectId`(`ID!`)
* `content`(`ReactionContent!`)

`!`는 `subjectId`와 `content`가 필수 필드임을 나타냅니다. 필수 `content`는 의미가 있습니다. 반응을 추가하려고 하므로 사용할 이모지 지정해야 합니다.

하지만 `subjectId`가 왜 필요한가요?
`subjectId`가 어떤 리포지토리의 어떤 이슈에 반응해야 하는지 식별하는 유일한 방법이기 때문입니다.\_\_\_\_

`ID`를 얻기 위해 쿼리를 사용하여 이 예제를 시작합니다.

쿼리를 한 줄씩 살펴보겠습니다.

* `query FindIssueID {`

  여기서는 쿼리를 수행하고 이름을 `FindIssueID`로 지정합니다. 쿼리 이름을 지정하는 것은 선택 사항입니다. 변경과 동일한 GUI 클라이언트 창에 포함할 수 있도록 여기에 이름을 지정합니다.

* `repository(owner:"octocat", name:"Hello-World") {`

`repository` 개체를 쿼리하고 `owner` 및 `name` 인수를 전달하여 리포지토리를 지정합니다.

* `issue(number:349) {`

`issue` 개체를 쿼리하고 `number` 인수를 전달하여 반응할 이슈를 지정합니다.

* `id`

  여기에서는 `id`에서 `https://github.com/octocat/Hello-World/issues/349`을(를) 검색하여 `subjectId`로 전달합니다.

쿼리를 실행하여 `id`: `MDU6SXNzdWUyMzEzOTE1NTE=`를 가져옵니다.

> \[!NOTE]
> 쿼리에서 반환되는 `id`가 변형에서 `subjectID`로서 전달할 값입니다. 문서나 스키마 내적 검사는 이 관계를 나타내지 않습니다. 이를 파악하려면 이름 뒤에 있는 개념을 이해해야 합니다.

ID를 알고 있으면 다음과 같이 변형을 진행할 수 있습니다.

* `mutation AddReactionToIssue {`

  여기서는 변형을 수행하고 이름을 `AddReactionToIssue`로 지정합니다. 쿼리와 마찬가지로 변경 이름 지정은 선택 사항입니다. 쿼리와 동일한 GUI 클라이언트 창에 포함할 수 있도록 여기에 이름을 지정합니다.

* `addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {`

  다음 줄을 살펴보겠습니다.

  * `addReaction`은 변형의 이름입니다.
  * `input`은 필수 인수 키입니다. 이 변형의 경우 항상 `input`입니다.
  * `{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}`는 필수 인수 키입니다. 이는 항상 뮤테이션을 위한 입력 필드(이 경우 `subjectId` 및 `content`)로 구성된 입력 객체이므로 중괄호를 사용합니다.

  콘텐츠에 사용할 값을 어떻게 알 수 있나요?
  [
  `addReaction` 문서](/ko/enterprise-server@3.22/graphql/reference/reactions#mutation-addreaction)에 따르면 `content` 필드의 형식은 [`ReactionContent`](/ko/enterprise-server@3.22/graphql/reference/reactions#enum-reactioncontent)이며, GitHub 이슈에서는 특정 이모지 반응만 지원되므로 이는 열거형입니다. 다음은 반응에 허용되는 값입니다(일부 값은 해당 이모지 이름과 다름).

  <table style="width:20%">
  <thead>
  <tr>
  <th scope="col" style="text-align:left">콘텐츠</th>
  <th scope="col" style="text-align:left">이모티콘</th>
  </tr>
  </thead>
  <tbody>
  <tr>
  <td style="text-align:left"><code>+1</code></td>
  <td style="text-align:left">👍</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>-1</code></td>
  <td style="text-align:left">👎</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>laugh</code></td>
  <td style="text-align:left">😄</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>confused</code></td>
  <td style="text-align:left">😕</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>heart</code></td>
  <td style="text-align:left">❤️</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>hooray</code></td>
  <td style="text-align:left">🎉</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>rocket</code></td>
  <td style="text-align:left">🚀</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>eyes</code></td>
  <td style="text-align:left">👀</td>
  </tr>
  </tbody>
  </table>

* 호출의 나머지는 페이로드 개체로 구성됩니다. 여기서는 변형을 수행한 후 서버에서 반환하도록 할 데이터를 지정합니다. 이러한 줄은 [`addReaction` 문서](/ko/enterprise-server@3.22/graphql/reference/reactions#mutation-addreaction)에서 오는 것이며, 다음 세 가지 가능한 반환 필드가 있습니다.

  * `clientMutationId`(`String`)
  * `reaction`(`Reaction!`)
  * `subject`(`Reactable!`)

  이 예제에서는 필수 하위 필드(각각 `reaction` 및 `subject`)가 있는 두 개의 필수 필드(`content` 및 `id`)를 반환합니다.

변형을 실행할 때 응답은 다음과 같습니다.

```json
{
  "data": {
    "addReaction": {
      "reaction": {
        "content": "HOORAY"
      },
      "subject": {
        "id": "MDU6SXNzdWUyMTc5NTQ0OTc="
      }
    }
  }
}
```

정말 간단하죠. 사용자 이름을 찾으려면 :tada를 마우스로 가리켜 [ 문제에 대한 반응](https://github.com/octocat/Hello-World/issues/349)을 확인합니다.

마지막으로, 입력 개체에 여러 필드를 전달하면 구문이 다루기 어려워질 수 있습니다. 필드를 [변수](#working-with-variables)로 이동하면 도움이 될 수 있습니다. 변수를 사용하여 원래 변형을 다시 작성하는 방법은 다음과 같습니다.

```graphql
mutation($myVar:AddReactionInput!) {
  addReaction(input:$myVar) {
    reaction {
      content
    }
    subject {
      id
    }
  }
}
variables {
  "myVar": {
    "subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
    "content":"HOORAY"
  }
}
```

> \[!NOTE]
> 이전 예제에서 `content` 필드 값(변형에서 직접 사용됨)에는 `HOORAY` 주위에 따옴표가 없지만, 변수에 사용될 때는 따옴표가 있는 것을 알 수 있습니다. 그 이유는 다음과 같습니다.
>
> * 변이에서 `content`를 직접 사용하는 경우, 스키마는 값이 문자열이 아닌 [`ReactionContent`](/ko/enterprise-server@3.22/graphql/reference/reactions#enum-reactioncontent) 형식의 \_열거형\_일 것으로 예상합니다. 따옴표는 문자열에 예약되어 있으므로 열거형 값 주위에 따옴표를 추가하면 스키마 유효성 검사에서 오류가 발생합니다.
> * 변수에서 `content`를 사용하는 경우, 변수 섹션은 유효한 JSON이어야 하므로 따옴표가 필요합니다. 스키마 유효성 검사는 실행 중에 변수가 변형으로 전달될 때 `ReactionContent` 형식을 올바르게 해석합니다.
>
> 열거형과 문자열 간의 차이점에 대한 자세한 내용은 [공식 GraphQL 사양](https://spec.graphql.org/June2018/#sec-Enums)을 참조하세요.

## 추가 참고 자료

GraphQL 호출을 구성할 때 할 수 있는 작업이 훨씬 더 많습니다.\_\_ 다음에 살펴볼 내용은 아래와 같습니다.

* [GraphQL API에서 페이지 매김 사용](/ko/enterprise-server@3.22/graphql/guides/using-pagination-in-the-graphql-api)
* [프래그먼트](https://graphql.org/learn/queries/#fragments)
* [인라인 프래그먼트](https://graphql.org/learn/queries/#inline-fragments)
* [지시문](https://graphql.org/learn/queries/#directives)