

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# GraphQL API의 구성 요소
<a name="api-components"></a>

표준 GraphQL API는 쿼리될 데이터의 형태를 처리하는 단일 스키마로 구성됩니다. 스키마는 데이터베이스 또는 Lambda 함수와 같은 하나 이상의 데이터 원본에 연결됩니다. 둘 사이에는 요청에 대한 비즈니스 로직을 처리하는 하나 이상의 해석기가 있습니다. 각 구성 요소는 GraphQL 구현에서 중요한 역할을 합니다. 다음 섹션에서는 이 세 가지 구성 요소와 GraphQL 서비스에서 수행하는 역할을 소개합니다.

![\[GraphQL API components: schema, resolvers, and data sources interconnected with AppSync.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/appsync-architecture-graphql-api.png)


**Topics**
+ [GraphQL 스키마](schema-components.md)
+ [데이터 원본](data-source-components.md)
+ [해석기](resolver-components.md)

# GraphQL 스키마
<a name="schema-components"></a>

GraphQL 스키마는 GraphQL API의 기반으로, 데이터의 형태를 정의하는 청사진 역할을 합니다. 또한 데이터를 검색 또는 수정하는 방법을 정의하는 클라이언트와 서버 간의 계약이기도 합니다.

GraphQL 스키마는 *스키마 정의 언어*(SDL)로 작성됩니다. SDL은 구조가 확립된 유형과 필드로 구성되어 있습니다.
+ **유형**: 유형은 GraphQL이 데이터의 형태와 동작을 정의하는 방식입니다. GraphQL은 이 섹션의 뒷부분에서 설명할 여러 유형을 지원합니다. 스키마에 정의된 각 유형에는 고유한 범위가 포함됩니다. 범위 내에는 GraphQL 서비스에서 사용할 값이나 로직을 포함할 수 있는 하나 이상의 필드가 있습니다. 유형은 다양한 역할을 수행하며, 가장 일반적으로는 객체 또는 스칼라(기본 값 유형) 역할을 합니다.
+ **필드**: 필드는 유형의 범위 내에 존재하며 GraphQL 서비스에서 요청한 값을 보유합니다. 이는 다른 프로그래밍 언어의 변수와 매우 유사합니다. 필드에 정의하는 데이터의 형태에 따라 요청/응답 작업에서 데이터가 구조화되는 방식이 결정됩니다. 이를 통해 개발자는 서비스의 백엔드가 구현되는 방식을 모르더라도 어떤 결과가 반환될지 예측할 수 있습니다.

스키마의 모습을 시각적으로 확인하기 위해 간단한 GraphQL 스키마의 내용을 살펴보겠습니다. 프로덕션 코드에서 스키마는 일반적으로 `schema.graphql` 또는 `schema.json`이라는 파일에 있습니다. GraphQL 서비스를 구현하는 프로젝트를 살펴본다고 가정해 보겠습니다. 이 프로젝트는 회사 직원 데이터를 저장하고 있으며, `schema.graphql` 파일은 직원 데이터를 검색하고 데이터베이스에 새 직원을 추가하는 데 사용됩니다. 코드는 다음과 같을 수 있습니다.

------
#### [ schema.graphql ]

```
type Person {                                  
   id: ID!
   name: String                                  
   age: Int
}
type Query {                                   
  people: [Person]
}
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

------

스키마에는 `Person`, `Query`, `Mutation`이라는 세 가지 유형이 정의되어 있는 것을 볼 수 있습니다. `Person`을 보면, 이 유형을 객체로 만드는 회사 직원 인스턴스의 청사진이라는 것을 짐작할 수 있습니다. 범위 내에는 `id`, `name`, `age`가 있습니다. 이러한 필드는 `Person`의 속성을 정의하는 필드입니다. 즉, 데이터 원본은 각 `Person`의 `name`을 `String` 스칼라(기본) 유형으로 저장하고 `age`를 `Int` 스칼라(기본) 유형으로 저장합니다. `id`는 각 `Person`에 대해 특별하고 고유한 식별자 역할을 합니다. 또한 `!` 기호로 표시되는 필수 값이기도 합니다.

다음 두 객체 유형은 다르게 동작합니다. GraphQL은 스키마에 데이터가 채워지는 방식을 정의하는 특수 객체 유형에 대한 몇 가지 키워드를 예약합니다. `Query` 유형은 소스에서 데이터를 검색합니다. 이 예에서는 쿼리가 데이터베이스에서 `Person` 객체를 검색할 수 있습니다. 이 작업은 RESTful 용어로 `GET` 작업을 떠올리게 할 수 있습니다. `Mutation`은 데이터를 수정합니다. 이 예에서는 변형으로 인해 데이터베이스에 더 많은 `Person` 객체가 추가될 수 있습니다. 이 작업은 `PUT` 또는 `POST`와 같은 상태 변경 작업을 떠올리게 할 수 있습니다. 모든 특수 객체 유형의 동작은 이 섹션의 뒷부분에서 설명합니다.

이 예제의 `Query`가 데이터베이스에서 무언가를 검색한다고 가정해 보겠습니다. `Query`의 필드를 살펴보면 `people`이라는 필드 하나를 볼 수 있습니다. 필드 값은 `[Person]`입니다. 즉, 데이터베이스에서 `Person`의 일부 인스턴스를 검색하려고 합니다. 하지만 대괄호를 추가하면 특정 인스턴스뿐만 아니라 모든 `Person` 인스턴스의 목록을 반환하게 됩니다.

`Mutation` 유형은 데이터 수정과 같은 상태 변경 작업을 수행하는 역할을 합니다. 변형은 데이터 원본에서 일부 상태 변경 작업을 수행하는 역할을 합니다. 이 예제에서 변형에는 데이터베이스에 새 `Person` 객체를 추가하는 `addPerson`이라는 작업이 포함되어 있습니다. 이 변형은 `Person`을 사용하며 `id`, `name`, `age` 필드에 대한 입력이 필요합니다.

이 시점에서 어떤 동작을 수행하며 함수 이름과 파라미터가 있는 함수와 매우 비슷해 보인다고 가정한다면 코드 구현 없이 `addPerson`과 같은 작업이 어떻게 작동하는지 궁금할 수 있습니다. 스키마는 선언 역할만 하기 때문에 지금은 작동하지 않습니다. `addPerson`의 동작을 구현하려면 해석기를 추가해야 합니다. 해석기는 관련 필드(이 경우 `addPerson` 작업)가 호출될 때마다 실행되는 코드 단위입니다. 작업을 사용하려면 어느 시점에 해석기 구현을 추가해야 합니다. 어떤 면에서는 스키마 작업을 함수 선언으로, 해석기는 정의로 생각할 수 있습니다. 해석기에 대해서는 다른 섹션에서 설명하겠습니다.

이 예제에서는 스키마가 데이터를 조작할 수 있는 가장 간단한 방법만 보여 줍니다. GraphQL 및 AWS AppSync의 기능을 활용하여 복잡하고 강력하며 확장 가능한 애플리케이션을 구축합니다. 다음 섹션에서는 스키마에서 활용할 수 있는 다양한 유형과 필드 동작을 모두 정의하겠습니다.

# GraphQL 유형
<a name="graphql-types"></a>

GraphQL은 다양한 유형을 지원합니다. 이전 섹션에서 보았듯이 유형은 데이터의 형태나 동작을 정의합니다. 유형은 GraphQL 스키마의 기본 구성 요소입니다.

유형은 입력과 출력으로 분류할 수 있습니다. 입력은 특수 객체 유형(`Query`, `Mutation` 등)에 대한 인수로 전달될 수 있는 유형인 반면, 출력 유형은 데이터를 저장하고 반환하는 데만 사용됩니다. 유형 및 분류 목록은 아래와 같습니다.
+ **객체**: 객체에는 엔터티를 설명하는 필드가 있습니다. 예를 들어 객체는 `authorName`, `publishingYear`와 같이 특성을 설명하는 필드가 있는 `book` 등이 될 수 있습니다. 이러한 유형은 엄밀히 말하면 출력 유형입니다.
+ **스칼라**: int, 문자열 등과 같은 기본 유형입니다. 일반적으로 필드에 할당됩니다. `authorName` 필드를 예로 들면 'John Smith'와 같은 이름을 저장하는 `String` 스칼라에 할당할 수 있습니다. 스칼라는 입력 유형과 출력 유형이 모두 될 수 있습니다.
+ **입력**: 입력을 사용하면 필드 그룹을 인수로 전달할 수 있습니다. 객체와 구조가 매우 비슷하지만, 특수 객체에 인수로 전달할 수 있습니다. 입력을 사용하면 범위에 스칼라, 열거형 및 기타 입력을 정의할 수 있습니다. 입력은 입력 유형만 가능합니다.
+ **특수 객체**: 특수 객체는 상태 변경 작업을 수행하며 서비스의 까다로운 작업 대부분을 수행합니다. 쿼리, 변형, 구독이라는 세 가지 특수 객체 유형이 있습니다. 일반적으로 쿼리는 데이터를 가져오고, 변형은 데이터를 조작하며, 구독은 지속적인 통신을 위해 클라이언트와 서버 간의 양방향 연결을 열고 유지합니다. 특수 객체는 기능으로 볼 때 입력도 출력도 아닙니다.
+ **열거형**: 열거형은 미리 정의된 유효 값 목록입니다. 열거형을 호출하는 경우 범위에 정의된 값만 열거형 값이 될 수 있습니다. 예를 들어 교통 신호 목록을 나타내는 `trafficLights`라는 열거형이 있는 경우 `redLight` 및 `greenLight`와 같은 값을 가질 수 있지만 `purpleLight` 값은 가질 수 없습니다. 실제 신호등에는 신호가 너무 많기 때문에 열거형을 사용하여 신호를 정의하고 `trafficLight`를 참조할 때 이러한 열거형만 유효 값이 되도록 할 수 있습니다. 열거형은 입력 유형과 출력 유형이 모두 될 수 있습니다.
+ **결합/인터페이스**: 결합을 사용하면 클라이언트가 요청한 데이터에 따라 요청에서 하나 이상의 항목을 반환할 수 있습니다. 예를 들어 `title` 필드가 포함된 `Book` 유형과 `name` 필드가 포함된 `Author` 유형이 있는 경우 두 유형 간에 결합을 생성할 수 있습니다. 클라이언트가 데이터베이스에서 'Julius Caesar'라는 문구를 쿼리하려는 경우 결합은 `Book` `title`에서 *Julius Caesar*(윌리엄 셰익스피어의 희곡)를 반환하고 `Author` `name`에서 *Julius Caesar*(*Commentarii de Bello Gallico*의 저자)를 반환할 수 있습니다. 결합은 출력 유형만 될 수 있습니다.

  인터페이스는 객체가 구현해야 하는 필드 집합으로, 인터페이스에 정의된 필드를 구현해야 하는 Java와 같은 프로그래밍 언어의 인터페이스와 약간 유사합니다. 예를 들어 `title` 필드를 포함하는 `Book`이라는 인터페이스를 만들었다고 가정해 보겠습니다. 이후 `Book`을 구현한 `Novel`이라는 유형을 만들었다고 가정합니다. `Novel`은 `title` 필드를 포함해야 합니다. 하지만 `Novel`은 `pageCount` 또는 `ISBN`와 같이 인터페이스에 없는 다른 필드도 포함할 수 있습니다. 인터페이스는 출력 유형만 될 수 있습니다.

다음 섹션에서는 GraphQL에서 각 유형이 작동하는 방식을 설명합니다.

## Objects
<a name="object-components"></a>

GraphQL 객체는 프로덕션 코드에서 볼 수 있는 기본 유형입니다. GraphQL에서는 객체를 다른 언어의 변수와 비슷한 여러 필드의 그룹으로 생각할 수 있으며, 각 필드는 값을 보유할 수 있는 유형(일반적으로 스칼라 또는 다른 객체)으로 정의됩니다. 객체는 서비스 구현에서 검색/조작할 수 있는 데이터 단위를 나타냅니다.

객체 유형은 `Type` 키워드를 사용하여 선언됩니다. 스키마 예제를 약간 수정해 보겠습니다.

```
type Person {
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

여기에서 객체 유형은 `Person` 및 `Occupation`입니다. 각 객체에는 고유한 유형이 있는 고유한 필드가 있습니다. GraphQL에는 필드를 다른 유형으로 설정할 수 있는 기능이 있습니다. `Person`의 `occupation` 필드에 `Occupation` 객체 유형이 포함되어 있는 것을 볼 수 있습니다. GraphQL은 데이터를 설명할 뿐 서비스 구현은 설명하지 않기 때문에 이렇게 연결할 수 있습니다.

## 스칼라
<a name="scalar-components"></a>

스칼라는 본질적으로 값을 보유하는 기본 유형입니다. 에는 기본 GraphQL 스칼라와 스칼라라는 두 AWS AppSync가지 유형의 AWS AppSync 스칼라가 있습니다. 스칼라는 일반적으로 객체 유형 내에 필드 값을 저장하는 데 사용됩니다. 기본 GraphQL 유형에는 `Int`, `Float`, `String`, `Boolean`, `ID`가 포함됩니다. 이전 예제를 다시 사용해 보겠습니다.

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

`name` 및 `title` 필드를 분리해 보면 둘 다 `String` 스칼라를 보유합니다. `Name`은 '`John Smith`'와 같은 문자열 값을 반환하고 제목은 '`firefighter`'와 같은 결과를 반환할 수 있습니다. 일부 GraphQL 구현에서는 `Scalar` 키워드를 사용하고 유형의 동작을 구현하는 사용자 지정 스칼라도 지원합니다. 그러나 지금은 AWS AppSync 에서 사용자 지정 스칼라를 **지원하지 않습니다**. 스칼라 목록은 [AWS AppSync의 스칼라 유형](https://docs.aws.amazon.com//appsync/latest/devguide/scalars.html)을 참조하세요.

## 입력
<a name="input-components"></a>

입력 및 출력 유형의 개념으로 인해 인수를 전달할 때 특정 제한이 발생합니다. 공통으로 전달해야 하는 유형, 특히 객체가 제한됩니다. 입력 유형을 사용하여 이 규칙을 우회할 수 있습니다. 입력은 스칼라, 열거형 및 기타 입력 유형을 포함하는 유형입니다.

입력은 `input` 키워드를 사용하여 정의됩니다.

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input personInput { 
  id: ID!
  name: String
  age: Int
  occupation: occupationInput
}

input occupationInput {
  title: String
}
```

보는 것과 같이 원래 유형을 모방하는 별도의 입력이 있을 수 있습니다. 이러한 입력은 다음과 같이 필드 작업에 자주 사용됩니다.

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

`Person`을 생성하기 위해 `Occupation`의 자리에 `occupationInput`을 계속해서 전달하는 방식을 주목하세요.

이 방식은 입력에 대한 한 가지 시나리오에 불과합니다. 객체를 반드시 1:1로 복사할 필요는 없으며, 프로덕션 코드에서는 이 방법으로 사용하지 않을 가능성이 큽니다. 입력해야 하는 항목만 인수로 정의하여 GraphQL 스키마를 활용하는 것이 좋습니다.

또한 동일한 입력을 여러 작업에 사용할 수 있지만 권장되지는 않습니다. 스키마의 요구 사항이 변경될 경우를 대비하여 각 작업에는 입력의 고유한 사본이 포함되는 것이 이상적입니다.

## 특수 객체
<a name="special-object-components"></a>

GraphQL은 스키마가 데이터를 검색/조작하는 방식에 대한 일부 비즈니스 로직을 정의하는 특수 객체를 위한 몇 가지 키워드를 예약합니다. 스키마에는 이러한 키워드가 최대 하나씩만 있을 수 있습니다. 이러한 키워드는 클라이언트가 GraphQL 서비스에 대해 실행하는 모든 요청 데이터의 진입점 역할을 합니다.

`type` 키워드를 사용하여 특수 객체도 정의합니다. 일반 객체 유형과는 다르게 사용되지만 구현은 매우 비슷합니다.

------
#### [ Queries ]

쿼리는 읽기 전용 가져오기를 수행하여 소스에서 데이터를 가져온다는 점에서 `GET` 작업과 매우 유사합니다. GraphQL에서 `Query`는 서버에 요청을 보내는 클라이언트의 모든 진입점을 정의합니다. GraphQL 구현에는 항상 `Query`가 있습니다.

다음은 이전 스키마 예제에서 사용한 `Query` 및 수정된 객체 유형입니다.

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
type Occupation {
  title: String
}
type Query {                                   
  people: [Person]
}
```

`Query`에는 데이터 원본의 `Person` 인스턴스 목록을 반환하는 `people`라는 필드가 포함되어 있습니다. 애플리케이션의 동작을 변경해야 하는데 이제 별도의 목적으로 `Occupation` 인스턴스 목록만 반환해야 한다고 가정해 보겠습니다. 쿼리에 간단히 추가할 수 있습니다.

```
type Query {                                   
  people: [Person]
  occupations: [Occupation]
}
```

GraphQL에서는 쿼리를 요청의 단일 소스로 취급할 수 있습니다. 보는 것과 같이 서로 다른 엔드포인트를 사용하여 동일한 결과(`.../api/1/people` 및 `.../api/1/occupations`)를 달성할 수 있는 RESTful 구현보다 훨씬 간단할 수 있습니다.

이 쿼리에 대한 해석기 구현이 있다고 가정하면 이제 실제 쿼리를 수행할 수 있습니다. `Query` 유형이 존재하지만 애플리케이션의 코드에서 실행되도록 하려면 명시적으로 호출해야 합니다. 다음과 같은 `query` 키워드를 사용하여 수행할 수 있습니다.

```
query getItems {
   people {
      name
   }
   occupations {
      title
   }
}
```

보는 것과 같이 이 쿼리는 `getItems`라고 하며 `people`(`Person` 객체의 목록) 및 `occupations`(`Occupation` 객체의 목록)를 반환합니다. `people`에서는 각 `Person`의 `name` 필드만 반환하는 반면, 각 `Occupation`의 `title` 필드를 반환합니다. 응답은 다음과 같을 수 있습니다.

```
{
  "data": {
    "people": [
      {
        "name": "John Smith"
      },
      {
        "name": "Andrew Miller"
      },
      .
      .
      .
    ],
    "occupations": [
      {
        "title": "Firefighter"
      },
      {
        "title": "Bookkeeper"
      },
      .
      .
      .
    ]
  }
}
```

예제 응답은 데이터가 쿼리의 형태를 어떻게 따르는지 보여 줍니다. 검색된 각 항목은 필드 범위 내에 나열됩니다. `people` 및 `occupations`는 항목을 별도의 목록으로 반환합니다. 이 방법이 유용하긴 하지만, 사람들의 이름과 직업 목록을 반환하도록 쿼리를 수정하는 것이 더 편리할 수도 있습니다.

```
query getItems {
   people {
      name   
      occupation {
        title
      }
}
```

`Person` 유형에 유형 `Occupation`의 `occupation` 필드가 포함되어 있기 때문에 이는 유효한 수정입니다. `people`의 범위 내에 나열되면 각 `Person`의 `name`과 함께 관련된 `Occupation`이 `title`별로 반환됩니다. 응답은 다음과 같을 수 있습니다.

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "occupation": {
          "title": "Firefighter"
        }
      },
      {
        "name": "Andrew Miller",
        "occupation": {
          "title": "Bookkeeper"
        }
      },
      .
      .
      .
    ]
  }
}
```

------
#### [ Mutations ]

변형은 `PUT` 또는 `POST`와 같은 상태 변경 작업과 비슷합니다. 이러한 작업은 쓰기 작업을 수행하여 소스의 데이터를 수정한 다음 응답을 가져옵니다. 또한 데이터 수정 요청의 진입점을 정의합니다. 쿼리와 달리 변형은 프로젝트의 필요에 따라 스키마에 포함되거나 포함되지 않을 수 있습니다. 다음은 스키마 예제의 변형입니다.

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

`addPerson` 필드는 데이터 원본에 `Person`을 추가하는 하나의 진입점을 나타냅니다. `addPerson`은 필드 이름이며 `id`, `name`, `age`는 파라미터, `Person`은 반환 유형입니다. `Person` 유형을 다시 살펴보면 다음과 같습니다.

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
```

`occupation` 필드를 추가했습니다. 하지만 객체를 인수로 전달할 수 없기 때문에 이 필드를 `Occupation`으로 직접 설정할 수는 없습니다. 엄밀히 말하면 출력 유형이기 때문입니다. 대신 인수와 동일한 필드를 포함하는 입력을 전달해야 합니다.

```
input occupationInput {
  title: String
}
```

 새 `Person` 인스턴스를 만들 때 이 필드를 파라미터로 포함하도록 `addPerson`을 간편하게 업데이트할 수도 있습니다.

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

업데이트된 스키마는 다음과 같습니다.

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

`occupation`은 `occupationInput`에서 `title` 필드를 전달하여 원래 `Occupation` 객체 대신 `Person` 생성을 완료합니다. `addPerson`에 대한 해석기 구현이 있다고 가정하면 이제 실제 변형을 수행할 수 있습니다. `Mutation` 유형이 존재하지만 애플리케이션의 코드에서 실행되도록 하려면 명시적으로 호출해야 합니다. 다음과 같은 `mutation` 키워드를 사용하여 수행할 수 있습니다.

```
mutation createPerson {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput) {
    name
    age
    occupation {
      title
    }
  }
}
```

이 변형을 `createPerson`이라고 하며 `addPerson`은 작업입니다. 새 `Person`을 만들려면 `id`, `name`, `age`, `occupation`의 인수를 입력하면 됩니다. `addPerson`의 범위에서는 `name`, `age` 등과 같은 다른 필드도 볼 수 있습니다. 응답은 다음과 같으며, 이러한 필드는 `addPerson` 작업이 완료된 후 반환됩니다. 예제의 마지막 부분은 다음과 같습니다.

```
mutation createPerson {
  addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner") {
    id
    name
    age
    occupation {
      title
    }
  }
}
```

이 변형을 사용하면 결과는 다음과 같을 수 있습니다.

```
{
  "data": {
    "addPerson": {
      "id": "1",
      "name": "Steve Powers",
      "age": "50",
      "occupation": {
        "title": "Miner"
      }
    }
  }
}
```

보는 것과 같이 응답은 요청한 값을 변형에 정의된 것과 동일한 형식으로 반환했습니다. 혼란을 줄이고 이후 더 많은 쿼리가 필요한 상황을 방지하기 위해 수정된 모든 값을 반환하는 것이 좋습니다. 변형을 사용하면 범위 내에 여러 작업을 포함할 수 있습니다. 변형에 나열된 순서대로 순차적으로 실행됩니다. 예를 들어 데이터 소스에 직함을 추가하는 `addOccupation`이라는 또 다른 작업을 만들면 `addPerson` 뒤에 변형에서 이를 직접적으로 호출할 수 있습니다. `addPerson`이 먼저 처리된 후 `addOccupation`이 처리됩니다.

------
#### [ Subscriptions ]

구독은 [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)을 사용하여 서버와 클라이언트 간의 지속적인 양방향 연결을 제공합니다. 일반적으로 클라이언트는 서버를 구독하거나 수신합니다. 서버에 서버 측 변경이 있거나 서버에서 이벤트를 수행할 때마다 구독한 클라이언트가 업데이트를 받게 됩니다. 이 유형의 프로토콜은 여러 클라이언트가 구독하고 서버나 다른 클라이언트에서 발생하는 변경 사항에 대해 알림을 받아야 하는 경우에 유용합니다. 예를 들어 구독을 사용하여 소셜 미디어 피드를 업데이트할 수 있습니다. 사용자 A와 사용자 B라는 두 명의 사용자가 있는데, 둘 다 다이렉트 메시지를 받을 때마다 자동 알림 업데이트를 받도록 구독합니다. 클라이언트 A의 사용자 A가 클라이언트 B의 사용자 B에게 다이렉트 메시지를 보냅니다. 사용자 A의 클라이언트가 다이렉트 메시지를 보내면 서버에서 처리됩니다. 그러면 서버는 사용자 B의 계정에 다이렉트 메시지를 보내고 클라이언트 B에는 자동 알림을 보냅니다.

다음은 스키마 예제에 추가할 수 있는 `Subscription`의 예입니다.

```
type Subscription {                                   
  personAdded: Person
}
```

이 `personAdded` 필드는 데이터 원본에 새 `Person`이 추가될 때마다 구독한 클라이언트에게 메시지를 보냅니다. `personAdded`에 대한 해석기 구현이 있다고 가정하면 이제 구독을 사용할 수 있습니다. `Subscription` 유형이 존재하지만 애플리케이션의 코드에서 실행되도록 하려면 명시적으로 호출해야 합니다. 다음과 같은 `subscription` 키워드를 사용하여 수행할 수 있습니다.

```
subscription personAddedOperation {
  personAdded {
    id
    name
  }
}
```

구독은 `personAddedOperation`이며, 작업은 `personAdded`입니다. `personAdded`는 새 `Person` 인스턴스의 `id` 및 `name` 필드를 반환합니다. 변형 예제를 살펴보면 이 작업을 사용하여 `Person`을 추가했습니다.

```
addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner")
```

클라이언트가 새로 추가된 `Person`에 대한 업데이트를 구독한 경우 `addPerson` 실행 후 다음과 같은 결과를 확인할 수 있습니다.

```
{
  "data": {
    "personAdded": {
      "id": "1",
      "name": "Steve Powers"
    }
  }
}
```

구독이 제공하는 내용을 요약하면 다음과 같습니다.

구독은 클라이언트와 서버가 빠르면서 안정적인 업데이트를 받을 수 있게 하는 양방향 채널입니다. 일반적으로 표준화되고 안전한 연결을 생성하는 WebSocket 프로토콜을 사용합니다.

구독은 연결 설정 오버헤드를 줄인다는 점에서 유연합니다. 구독하면 클라이언트는 해당 구독을 오랫동안 계속 사용할 수 있습니다. 대부분의 경우 개발자가 구독 기간을 조정하고 요청할 정보를 구성할 수 있도록 함으로써 컴퓨팅 리소스를 효율적으로 사용합니다.

일반적으로 구독을 통해 클라이언트는 한 번에 여러 구독을 설정할 수 있습니다. 이와 관련하여 AWS AppSync구독은 AWS AppSync 서비스로부터 실시간 업데이트를 수신하는 데에만 사용됩니다. 쿼리나 변형을 수행하는 데는 사용할 수 없습니다.

구독의 주요 대안은 지정된 간격으로 쿼리를 전송하여 데이터를 요청하는 폴링입니다. 이 프로세스는 일반적으로 구독보다 덜 효율적이며 클라이언트와 백엔드 모두에 많은 부담을 줍니다.

------

스키마 예제에서 언급되지 않은 한 가지는 특수 객체 유형도 `schema` 루트에 정의되어야 한다는 사실입니다. 따라서 스키마를 내보낼 때 다음과 같 AWS AppSync을 수 있습니다.

------
#### [ schema.graphql ]

```
schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

.
.
.

type Query {                                   
  # code goes here
}
type Mutation {                                   
  # code goes here
}
type Subscription {                                   
  # code goes here
}
```

------

## 열거
<a name="enum-components"></a>

열거 또는 열거형은 유형이나 필드에 사용할 수 있는 유효한 인수를 제한하는 특수 스칼라입니다. 즉, 스키마에 열거형이 정의될 때마다 관련 유형이나 필드가 열거형의 값으로 제한됩니다. 열거형은 문자열 스칼라로 직렬화됩니다. 프로그래밍 언어에 따라 GraphQL 열거형을 다르게 처리할 수 있다는 점에 유의하세요. 예를 들어 JavaScript에는 기본 열거형 지원이 없으므로 열거형 값을 int 값에 대신 매핑할 수 있습니다.

열거형은 `enum` 키워드를 사용하여 정의됩니다. 다음은 그 예입니다.

```
enum trafficSignals {
  solidRed
  solidYellow
  solidGreen
  greenArrowLeft
  ...
}
```

`trafficLights` 열거형을 호출할 때 인수는 `solidRed`, `solidYellow`, `solidGreen` 등만 사용할 수 있습니다. 명확하지만 제한된 수의 선택 사항이 있는 항목을 묘사하는 데 열거형을 사용하는 것이 일반적입니다.

## 결합/인터페이스
<a name="union-interface-components"></a>

GraphQL의 [인터페이스 및 결합](https://docs.aws.amazon.com/appsync/latest/devguide/interfaces-and-unions.html)을 참조하세요.

# GraphQL 필드
<a name="graphql-fields"></a>

필드는 유형의 범위 내에 존재하며 GraphQL 서비스에서 요청한 값을 보유합니다. 이는 다른 프로그래밍 언어의 변수와 매우 유사합니다. 예를 들어, `Person` 객체 유형은 다음과 같습니다.

```
type Person {                                  
   name: String                                  
   age: Int
}
```

이 경우 필드는 `name` 및 `age`이고 각각 `String` 및 `Int` 값을 보유합니다. 위에 표시된 것과 같은 객체 필드를 쿼리 및 변형의 필드(작업)에서 입력으로 사용할 수 있습니다. 그 예로 아래 `Query`를 참조하세요.

```
type Query {                                   
  people: [Person]
}
```

`people` 필드는 데이터 원본의 `Person`에 있는 모든 인스턴스를 요청합니다. GraphQL 서버에서 `Person`을 추가하거나 검색할 때 데이터가 유형 및 필드의 형식을 따를 것으로 예상할 수 있습니다. 즉, 스키마의 데이터 구조에 따라 응답에서 데이터가 구조화되는 방식이 결정됩니다.

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "age": "50"
      },
      {
        "name": "Andrew Miller",
        "age": "60"
      },
      .
      .
      .
    ]
  }
}
```

필드는 데이터를 구조화하는 데 중요한 역할을 합니다. 추가 사용자 지정을 위해 필드에 적용할 수 있는 몇 가지 추가 속성이 아래에 설명되어 있습니다.

## Lists
<a name="list-components"></a>

목록은 지정된 유형의 모든 항목을 반환합니다. 대괄호 `[]`를 사용하여 필드 유형에 목록을 추가할 수 있습니다.

```
type Person { 
  name: String
  age: Int
}
type Query {                                   
  people: [Person]
}
```

`Query`에서 `Person` 주위의 대괄호는 데이터 원본의 `Person`에 있는 모든 인스턴스를 배열로 반환한다는 것을 나타냅니다. 응답에서 각 `Person`의 `name` 및 `age` 값은 구분된 단일 목록으로 반환됩니다.

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",         # Data of Person 1
        "age": "50"
      },
      {
        "name": "Andrew Miller",      # Data of Person 2
        "age": "60"
      },
      .                               # Data of Person N
      .
      .
    ]
  }
}
```

특수 객체 유형에만 국한되지 않습니다. 일반 객체 유형의 필드에서도 목록을 사용할 수 있습니다.

## null 아님
<a name="non-null-components"></a>

null 아님 필드는 응답에서 null이 될 수 없는 필드를 나타냅니다. `!` 기호를 사용하여 필드를 null이 아닌 필드로 설정할 수 있습니다.

```
type Person { 
  name: String!
  age: Int
}
type Query {                                   
  people: [Person]
}
```

`name` 필드는 명시적으로 null이 될 수 없습니다. 데이터 원본을 쿼리하고 이 필드에 null 입력을 제공하면 오류가 발생합니다.

목록과 null이 아닌 필드를 조합할 수 있습니다. 다음 쿼리를 비교해 보세요.

```
type Query {                                   
  people: [Person!]      # Use case 1
}

.
.
.

type Query {                                   
  people: [Person]!      # Use case 2
}

.
.
.

type Query {                                   
  people: [Person!]!     # Use case 3
}
```

사용 사례 1에서는 목록에 null 항목을 포함할 수 없습니다. 사용 사례 2에서는 목록 자체를 null로 설정할 수 없습니다. 사용 사례 3에서는 목록과 해당 항목이 null일 수 없습니다. 하지만 어떤 경우에도 빈 목록을 반환할 수 있습니다.

보는 것과 같이 GraphQL에는 움직이는 구성 요소가 많이 있습니다. 이 섹션에서는 간단한 스키마의 구조와 스키마가 지원하는 여러 유형 및 필드를 보여드렸습니다. 다음 섹션에서는 GraphQL API의 기타 구성 요소와 이러한 구성 요소가 스키마에서 작동하는 방식에 대해 알아봅니다.

# 데이터 원본
<a name="data-source-components"></a>

이전 섹션에서는 스키마가 데이터의 형태를 정의한다는 것을 배웠습니다. 하지만 해당 데이터의 출처는 설명하지 않았습니다. 실제 프로젝트에서 스키마는 서버에 대한 모든 요청을 처리하는 게이트웨이와 같습니다. 요청이 생성되면 스키마는 클라이언트와 인터페이스하는 단일 엔드포인트 역할을 합니다. 스키마는 데이터 원본의 데이터에 액세스하며 데이터를 처리하고 다시 클라이언트로 전달합니다. 아래 인포그래픽을 참조하세요.

![\[GraphQL schema integrating multiple AWS 서비스 for a single endpoint API architecture.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/aws-flow-infographic.png)


AWS AppSync 및 GraphQL은 프런트엔드용 백엔드(BFF) 솔루션을 완벽하게 구현합니다. 이러한 기능은 함께 작동하여 백엔드를 추상화하여 대규모로 복잡성을 줄입니다. 서비스가 다양한 데이터 원본 또는 마이크로서비스를 사용하는 경우 각 소스(서브그래프)의 데이터 형태를 단일 스키마(수퍼그래프)로 정의하여 기본적으로 복잡성을 어느 정도 추상화할 수 있습니다. 즉, GraphQL API는 하나의 데이터 원본을 사용하도록 제한되지 않습니다. 원하는 수의 데이터 원본을 GraphQL API와 연결하고 해당 데이터 원본이 서비스와 상호 작용하는 방식을 코드에 지정할 수 있습니다.

인포그래픽에서 볼 수 있듯이 GraphQL 스키마에는 클라이언트가 데이터를 요청하는 데 필요한 모든 정보가 포함되어 있습니다. 즉, REST의 경우처럼 여러 요청을 처리하는 대신 단일 요청으로 모든 작업을 처리할 수 있습니다. 이러한 요청은 서비스의 유일한 엔드포인트인 스키마를 거칩니다. 요청이 처리되면 해석기(다음 섹션에서 설명함)가 코드를 실행하여 관련 데이터 원본의 데이터를 처리합니다. 응답이 반환되면 데이터 원본에 연결된 서브그래프가 스키마의 데이터로 채워집니다.

AWS AppSync 는 다양한 데이터 소스 유형을 지원합니다. 아래 테이블에서는 각 유형에 대해 설명하고, 각 유형의 이점을 나열하고, 추가 컨텍스트를 위한 유용한 링크를 제공합니다.


| 데이터 소스 | 설명 | 이점 | 추가 정보 | 
| --- | --- | --- | --- | 
| Amazon DynamoDB | “Amazon DynamoDB는 완전관리형 NoSQL 데이터베이스 서비스로서 원활한 확장성과 함께 빠르고 예측 가능한 성능을 제공합니다. DynamoDB는 분산 데이터베이스를 운영하고 크기 조정하는 데 따른 관리 부담을 줄여서 하드웨어 프로비저닝, 설정 및 구성, 복제, 소프트웨어 패치 또는 클러스터 크기 조정에 대해 걱정할 필요가 없게 합니다. 또한 DynamoDB는 유휴 시 암호화를 제공하여 중요한 데이터 보호와 관련된 운영 부담 및 복잡성을 제거합니다.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  | 
| AWS Lambda | AWS Lambda "는 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있는 컴퓨팅 서비스입니다.Lambda는 고가용성 컴퓨팅 인프라에서 코드를 실행하고 서버와 운영 체제 유지 관리, 용량 프로비저닝 및 자동 조정, 코드 및 보안 패치 배포, 로깅 등 모든 컴퓨팅 리소스 관리를 수행합니다. Lambda를 사용하면 Lambda가 지원하는 언어 런타임 중 하나로 코드를 제공하기만 하면 됩니다.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  | 
| OpenSearch | “Amazon OpenSearch Service는 AWS 클라우드에서 OpenSearch 클러스터를 쉽게 배포, 운영 및 확장할 수 있는 관리형 서비스입니다. Amazon OpenSearch Service는 OpenSearch 및 레거시 Elasticsearch OSS(소프트웨어의 최종 오픈 소스 버전인 7.10까지)를 지원합니다. 클러스터를 생성할 때 어떤 검색 엔진을 사용할지 선택할 수 있습니다.**OpenSearch**는 로그 분석, 실시간 애플리케이션 모니터링, 클릭 스트림 분석 같은 사용 사례를 위한 완전한 오픈 소스 검색 및 분석 엔진입니다. 자세한 내용은 [OpenSearch 설명서](https://opensearch.org/docs/)를 참조하세요.**Amazon OpenSearch Service**는 OpenSearch 클러스터에 대한 모든 리소스를 프로비저닝하고 시작합니다. 또한 실패한 OpenSearch Service 노드를 자동으로 감지한 다음 교체해 자체 관리형 인프라와 관련된 오버헤드를 줄입니다. API를 한 번만 호출하거나 콘솔에서 몇 번만 클릭하여 클러스터를 조정할 수 있습니다.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  | 
| HTTP 엔드포인트 | HTTP 엔드포인트를 데이터 소스로 사용할 수 있습니다. AWS AppSync는 파라미터 및 페이로드와 같은 관련 정보를 사용하여 엔드포인트에 요청을 보낼 수 있습니다. HTTP 응답은 해석기에 노출되며, 해석기는 작업이 완료된 후 최종 응답을 반환합니다. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  | 
| Amazon EventBridge | “EventBridge는 이벤트를 사용하여 애플리케이션 구성 요소를 서로 연결하는 서버리스 서비스로, 확장 가능한 이벤트 기반 애플리케이션을 더 쉽게 구축할 수 있습니다. 이를 사용하여 자체 개발 애플리케이션, AWS 서비스 및 타사 소프트웨어와 같은 소스의 이벤트를 조직 전체의 소비자 애플리케이션으로 라우팅할 수 있습니다. EventBridge는 이벤트를 수집, 필터링, 변환 및 전달하는 간단하고 일관된 방법을 제공하므로 새로운 애플리케이션을 빠르게 빌드할 수 있습니다.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  | 
| 관계형 데이터베이스 | “Amazon Relational Database Service(RDS)는 AWS 클라우드에서 관계형 데이터베이스를 더 쉽게 설정, 운영 및 확장할 수 있는 웹 서비스입니다. 이 서비스는 산업 표준 관계형 데이터베이스를 위한 경제적이고 크기 조절이 가능한 용량을 제공하고 공통 데이터베이스 관리 작업을 관리합니다.” |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  | 
| 데이터 원본 사용 안 함 | 데이터 원본 서비스를 사용할 계획이 없다면 none으로 설정할 수 있습니다. 명시적으로는 여전히 데이터 소스로 분류되지만 none 데이터 원본은 저장 매체가 아닙니다. 그럼에도 불구하고 특정 상황에서는 데이터 조작 및 패스스루에 여전히 유용합니다. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/data-source-components.html)  | 

**작은 정보**  
데이터 소스가 상호 작용하는 방식에 대한 자세한 내용은 데이터 소스 연결을 AWS AppSync참조하세요. [https://docs.aws.amazon.com//appsync/latest/devguide/attaching-a-data-source.html](https://docs.aws.amazon.com//appsync/latest/devguide/attaching-a-data-source.html) 

# 해석기
<a name="resolver-components"></a>

이전 섹션에서 스키마와 데이터 원본의 구성 요소에 대해 알아보았습니다. 이제 스키마와 데이터 원본이 상호 작용하는 방식을 알아보겠습니다. 모든 작업은 해석기에서 시작됩니다.

해석기는 서비스에 요청이 들어왔을 때 해당 필드의 데이터가 해석되는 방식을 처리하는 코드 단위입니다. 해석기는 스키마의 유형 내 특정 필드에 연결됩니다. 쿼리, 변형 및 구독 필드 작업의 상태 변경 작업을 구현하는 데 가장 일반적으로 사용됩니다. 해석기는 클라이언트의 요청을 처리한 다음 결과를 반환하며, 결과는 객체 또는 스칼라와 같은 출력 유형 그룹일 수 있습니다.

![\[GraphQL schema with resolvers connecting to various AWS data sources for a single endpoint.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/aws-flow-infographic.png)


## 해석기 런타임
<a name="resolver-components-runtime"></a>

에서는 먼저 해석기의 런타임을 지정 AWS AppSync해야 합니다. 해석기 런타임은 해석기가 실행되는 환경을 나타냅니다. 또한 해석기가 작성될 언어를 지정합니다. AWS AppSync 현재는 JavaScript용 APPSYNC\$1JS 및 VTL(Velocity Template Language)을 지원합니다. JavaScript용 [해석기 및 함수에 대한 JavaScript 런타임 기능](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html) 또는 VTL용 [해석기 매핑 템플릿 유틸리티 참조](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html)를 참조하세요.

## 해석기 구조
<a name="resolver-components-structure"></a>

코드와 관련해서는 해석기를 몇 가지 방식으로 구성할 수 있습니다. **단위** 해석기와 **파이프라인** 해석기가 있습니다.

### 단위 해석기
<a name="resolver-components-unit"></a>

단위 해석기는 데이터 원본에 대해 실행되는 단일 요청 및 응답 핸들러를 정의하는 코드로 구성됩니다. 요청 핸들러는 컨텍스트 객체를 인수로 사용하고 데이터 원본을 호출하는 데 사용된 요청 페이로드를 반환합니다. 응답 핸들러는 실행된 요청의 결과와 함께 데이터 소스로부터 페이로드를 다시 받습니다. 응답 핸들러는 페이로드를 GraphQL 응답으로 변환하여 GraphQL 필드를 해석합니다.

![\[GraphQL request flow showing request and response handlers interacting with a data source.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/unit-resolver-js.png)


### 파이프라인 해석기
<a name="resolver-components-pipeline"></a>

파이프라인 해석기를 구현할 때는 다음과 같은 일반적인 구조를 따릅니다.
+ **사전 단계**: 클라이언트가 요청을 보내면 사용 중인 스키마 필드(일반적으로 쿼리, 변형, 구독)의 해석기에 요청 데이터가 전달됩니다. 해석기는 데이터가 해석기를 통해 이동하기 전에 일부 사전 처리 작업을 수행할 수 있는 사전 단계 핸들러를 사용하여 요청 데이터 처리를 시작합니다.
+ **함수:** 사전 단계가 실행되면 요청이 함수 목록으로 전달됩니다. 목록의 첫 번째 함수는 데이터 원본에 대해 실행됩니다. 함수는 자체 요청 및 응답 핸들러를 포함하는 해석기 코드의 하위 집합입니다. 요청 핸들러는 요청 데이터를 가져와 데이터 원본에 대해 작업을 수행합니다. 응답 핸들러는 데이터 원본의 응답을 다시 목록으로 전달하기 전에 해당 데이터 원본의 응답을 처리합니다. 함수가 두 개 이상인 경우 요청 데이터는 목록의 다음 함수로 전송되어 실행됩니다. 목록에 있는 함수는 개발자가 정의한 순서대로 순차적으로 실행됩니다. 모든 함수가 실행되면 최종 결과가 사후 단계로 전달됩니다.
+ **사후 단계**: 사후 단계는 GraphQL 응답으로 전달하기 전에 최종 함수의 응답에 대한 몇 가지 최종 작업을 수행할 수 있는 핸들러 함수입니다.

![\[GraphQL request flow diagram showing interactions between request, data sources, and response components.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/appsync-js-resolver-logic.png)


## 해석기 핸들러 구조
<a name="resolver-components-handlers"></a>

핸들러는 일반적으로 `Request` 및 `Response`라는 함수입니다.

```
export function request(ctx) {
    // Code goes here
}

export function response(ctx) {
    // Code goes here
}
```

단위 해석기에는 이러한 함수 집합이 하나뿐입니다. 파이프라인 해석기에는 사전 단계와 사후 단계를 위한 이러한 함수 집합이 있고 함수별로 추가 집합이 있습니다. 시각적으로 확인해 볼 수 있도록 간단한 `Query` 유형을 살펴보겠습니다.

```
type Query {
	helloWorld: String!
}
```

이 쿼리는 유형 `String`의 `helloWorld`라는 필드 하나가 있는 간단한 쿼리입니다. 이 필드가 항상 'Hello World'라는 문자열을 반환하게 한다고 가정해 보겠습니다. 이 동작을 구현하려면 이 필드에 해석기를 추가해야 합니다. 단위 해석기에서는 다음과 같이 추가할 수 있습니다.

```
export function request(ctx) {
    return {}
}

export function response(ctx) {
    return "Hello World"
}
```

데이터를 요청하거나 처리하지 않기 때문에 `request`는 비워 두어도 됩니다. 또한 데이터 원본이 `None`이라고 가정할 수도 있는데, 이 코드를 간접 호출할 필요가 없다는 뜻입니다. 응답은 단순히 'Hello World'를 반환합니다. 이 해석기를 테스트하려면 다음 쿼리 유형을 사용하여 요청해야 합니다.

```
query helloWorldTest {
  helloWorld
}
```

이 쿼리는 `helloWorld` 필드를 반환하는 `helloWorldTest`라는 쿼리입니다. `helloWorld` 필드 해석기는 또한 실행 시 다음 응답을 실행하고 반환합니다.

```
{
  "data": {
    "helloWorld": "Hello World"
  }
}
```

이와 같은 상수를 반환하는 작업은 가장 간단하게 할 수 있는 작업입니다. 실제로는 입력, 목록 등을 반환하게 됩니다. 더 복잡한 예는 다음과 같습니다.

```
type Book {
  id: ID!
  title: String
}

type Query {
  getBooks: [Book]
}
```

여기서는 `Books`의 목록을 반환합니다. DynamoDB 테이블을 사용하여 책 데이터를 저장한다고 가정해 보겠습니다. 핸들러는 다음과 같을 수 있습니다.

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

요청은 내장된 스캔 작업을 사용하여 테이블의 모든 항목을 검색하고 결과를 컨텍스트에 저장한 다음 응답으로 전달했습니다. 응답은 결과 항목을 가져와 응답에 반환했습니다.

```
{
  "data": {
    "getBooks": {
      "items": [
        {
          "id": "abcdefgh-1234-1234-1234-abcdefghijkl",
          "title": "book1"
        },
        {
          "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
          "title": "book2"
        },

        ...

      ]
    }
  }
}
```

## 해석기 컨텍스트
<a name="resolver-components-context"></a>

해석기에서 핸들러 체인의 각 단계에서는 이전 단계의 데이터 상태를 알고 있어야 합니다. 한 핸들러의 결과를 저장하고 다른 핸들러에 인수로 전달할 수 있습니다. GraphQL은 네 가지 기본 해석기 인수를 정의합니다.


****  

| 해석기 기본 인수 | 설명 | 
| --- | --- | 
| obj, root, parent 등. | 상위 항목의 결과입니다. | 
| args | GraphQL 쿼리의 필드에 제공된 인수입니다. | 
| context | 모든 해석기에 제공되며 현재 로그인한 사용자 또는 데이터베이스 액세스와 같은 중요한 컨텍스트 정보를 보유하는 값입니다. | 
| info | 현재 쿼리와 관련된 필드별 정보와 스키마 세부 정보를 포함하는 값입니다. | 

에서 `[context](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)` (ctx) 인수 AWS AppSync는 위에서 언급한 모든 데이터를 포함할 수 있습니다. 요청별로 생성되는 객체이며 권한 부여 보안 인증, 결과 데이터, 오류, 요청 메타데이터 등과 같은 데이터를 포함합니다. 컨텍스트는 프로그래머가 요청의 다른 부분에서 오는 데이터를 조작할 수 있는 간단한 방법입니다. 이 스니펫을 다시 살펴보세요.

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

요청에는 컨텍스트(ctx)가 인수로 제공되는데, 이는 요청의 상태입니다. 테이블의 모든 항목을 스캔한 다음 `result`의 컨텍스트에 결과를 다시 저장합니다. 그러면 컨텍스트가 응답 인수로 전달되고, 응답 인수는 `result`에 액세스하여 내용을 반환합니다.

## 요청 및 구문 분석
<a name="resolver-ast"></a>

GraphQL 서비스에 쿼리를 생성하는 경우 먼저 구문 분석 및 검증 프로세스를 거친 후 실행해야 합니다. 요청이 구문 분석되고 추상 구문 트리로 번역됩니다. 스키마에 대해 여러 검증 알고리즘을 실행하여 트리의 내용을 검증합니다. 검증 단계가 완료되면 트리의 노드를 순회하여 처리합니다. 해석기가 간접적으로 호출되고, 결과가 컨텍스트에 저장되며, 응답이 반환됩니다. 다음 쿼리를 예로 들어 보겠습니다.

```
query {
  Person {  //object type
    name  //scalar
    age   //scalar
  } 
}
```

`name` 및 `age` 필드와 함께 `Person`이 반환됩니다. 이 쿼리를 실행하면 다음과 같은 트리가 나옵니다.

![\[Hierarchical diagram showing query, Person, name, and age nodes connected by arrows.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/ast-1.png)


트리에서 보면 이 요청이 스키마의 루트에서 `Query`를 검색하는 것으로 보입니다. 쿼리 내에서 `Person` 필드가 해석됩니다. 이전 예제를 보면 사용자의 입력, 값 목록 등일 수 있습니다. `Person`은 필요한 필드(`name` 및 `age`)를 보유하는 객체 유형과 연결되어 있을 가능성이 높습니다. 이 두 개의 하위 필드를 찾으면 주어진 순서대로(`name` 다음 `age`) 해석됩니다. 트리가 완전히 해석되면 요청이 완료되고 클라이언트에게 다시 전송됩니다.