

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

# 를 사용하여 GraphQL APIs 설계 AWS AppSync
<a name="designing-a-graphql-api"></a>

AWS AppSync 를 사용하면 콘솔 환경을 사용하여 GraphQL APIs를 생성할 수 있습니다. [샘플 스키마 시작](https://docs.aws.amazon.com/appsync/latest/devguide/quickstart.html) 섹션에서 이 내용을 간략히 살펴보았습니다. 그러나이 가이드에는 활용할 수 있는 옵션 및 구성의 전체 카탈로그가 표시되지 않았습니다 AWS AppSync.

콘솔에서 GraphQL API를 생성하는 경우 살펴보아야 할 몇 가지 옵션이 있습니다. [샘플 스키마 시작](https://docs.aws.amazon.com/appsync/latest/devguide/quickstart.html) 가이드에서는 사전 정의된 모델에서 API를 생성하는 방법을 알아보았습니다. 다음 섹션에서는 AWS AppSync에서 GraphQL API를 생성하기 위한 나머지 옵션과 구성을 안내합니다.

이 섹션에서는 다음 개념을 검토하게 됩니다.

1. [Blank APIs or imports](blank-import-api.md#aws-appsync-blank-import-api): 이 가이드는 GraphQL API를 만들기 위한 전체 생성 프로세스를 안내합니다. 모델 없이 빈 템플릿에서 GraphQL을 생성하고, 스키마의 데이터 소스를 구성하고, 필드에 첫 번째 해석기를 추가하는 방법을 알아봅니다.

1. [Real-time data](aws-appsync-real-time-data.md#aws-appsync-real-time-data-anchor):이 가이드에서는 AWS AppSync의 WebSocket 엔진을 사용하여 API를 생성하는 잠재적 옵션을 보여줍니다.

1. [Merged APIs](merged-api.md#aws-appsync-merged-api): 이 가이드에서는 여러 기존 GraphQL API의 데이터를 연결하고 병합하여 새 GraphQL API를 만드는 방법을 보여줍니다.

1. [RDS 내부 검사를 통한 GraphQL API 빌드](rds-introspection.md): 이 가이드에서는 데이터 API를 사용하여 Amazon RDS 테이블을 통합하는 방법을 보여줍니다.

# GraphQL API 구조화(빈 API 또는 가져온 API)
<a name="blank-import-api"></a>

빈 템플릿에서 GraphQL API를 생성하기 전에 GraphQL과 관련된 개념을 검토하는 것이 도움이 될 것입니다. GraphQL API에는 세 가지 기본 구성 요소가 있습니다.

1. **스키마**는 데이터의 형태와 정의를 포함하는 파일입니다. 클라이언트가 GraphQL 서비스에 요청을 보내면 반환되는 데이터는 스키마의 사양을 따릅니다. 자세한 내용은 [GraphQL 스키마](schema-components.md#aws-appsync-schema-components) 단원을 참조하십시오.

1. **데이터 소스**는 스키마에 연결되어 있습니다. 요청이 만들어지면 여기에서 데이터를 검색하고 수정합니다. 자세한 내용은 [데이터 원본](data-source-components.md#aws-appsync-data-source-components) 단원을 참조하십시오.

1. **해석기**는 스키마와 데이터 소스 사이에 위치합니다. 요청이 만들어지면 해석기는 소스의 데이터에 대해 작업을 수행한 다음 응답으로 결과를 반환합니다. 자세한 내용은 [해석기](resolver-components.md#aws-appsync-resolver-components) 단원을 참조하십시오.

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


AWS AppSync 는 스키마 및 해석기에 대한 코드를 생성, 편집 및 저장할 수 있도록 하여 APIs를 관리합니다. 데이터 소스는 데이터베이스, DynamoDB 테이블, Lambda 함수와 같은 외부 리포지토리에서 가져옵니다. AWS 서비스를 사용하여 데이터를 저장하거나 저장할 계획인 경우는 AWS 계정의 데이터를 GraphQL APIs에 연결할 때 거의 원활한 환경을 AWS AppSync 제공합니다.

다음 섹션에서는 AWS AppSync 서비스를 사용하여 이러한 각 구성 요소를 생성하는 방법을 알아봅니다.

**Topics**
+ [GraphQL 스키마 설계](designing-your-schema.md)
+ [데이터 소스 연결](attaching-a-data-source.md)
+ [AWS AppSync 해석기 구성](resolver-config-overview.md)
+ [CDK에서 API 사용](using-your-api.md)

# GraphQL 스키마 설계
<a name="designing-your-schema"></a>

GraphQL 스키마는 모든 GraphQL 서버 구현의 기초입니다. 각 GraphQL API는 요청의 데이터가 채워지는 방식을 설명하는 유형과 필드를 포함하는 **단일** 스키마로 정의됩니다. API를 통한 데이터 흐름과 수행되는 작업은 스키마를 기준으로 검증되어야 합니다.

[GraphQL 유형 시스템](https://graphql.org/learn/schema/#type-system)은 일반적으로 GraphQL 서버의 기능을 기술하고 쿼리가 유효한지 확인하는 데 사용됩니다. 서버의 유형 시스템은 종종 해당 서버의 스키마라고 하며 다양한 객체 유형, 스칼라 유형, 입력 유형 등으로 구성될 수 있습니다. GraphQL은 선언적이면서 강력한 유형입니다. 즉, 유형은 런타임에 잘 정의되고 지정된 값만 반환합니다.

AWS AppSync 를 사용하면 GraphQL 스키마를 정의하고 구성할 수 있습니다. 다음 섹션에서는 AWS AppSync의 서비스를 사용하여 GraphQL 스키마를 처음부터 생성하는 방법을 설명합니다.

## GraphQL 스키마 구조화
<a name="schema-structure"></a>

**작은 정보**  
계속하기 전에 [스키마](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html) 섹션을 검토하는 것이 좋습니다.

GraphQL은 API 서비스를 구현하기 위한 강력한 도구입니다. [GraphQL의 웹 사이트](https://graphql.org/)에서는 GraphQL을 다음과 같이 기술합니다.

“GraphQL은 API용 쿼리 언어이자 기존 데이터로 이러한 쿼리를 수행하기 위한 런타임입니다.* GraphQL은 API의 데이터에 대한 완전하고 이해하기 쉬운 설명을 제공하고, 클라이언트가 필요한 사항과 더 이상 필요하지 않은 사항을 정확히 요청할 수 있는 기능을 제공하며, 시간이 지남에 따라 API를 더 쉽게 발전시킬 수 있게 하고, 강력한 개발자 도구를 사용할 수 있도록 합니다.”*

이 섹션에서는 GraphQL 구현의 맨 첫 부분인 스키마를 다룹니다. 위의 인용문에 따르면 스키마는 'API의 데이터에 대한 완전하고 이해하기 쉬운 설명을 제공'하는 역할을 합니다. 즉, GraphQL 스키마는 서비스의 데이터, 작업 및 작업 간의 관계를 텍스트로 표현한 것입니다. 스키마는 GraphQL 서비스 구현을 위한 기본 진입점으로 간주됩니다. 당연하게도 스키마는 프로젝트에서 가장 먼저 만드는 항목 중 하나인 경우가 많습니다. 계속하기 전에 [스키마](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html) 섹션을 검토하는 것이 좋습니다.

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

가장 간단한 스키마에는 다음과 같은 세 가지 데이터 범주가 포함됩니다.

1. **스키마 루트**: 루트는 스키마의 진입점을 정의합니다. 또한 추가, 삭제, 수정과 같은 데이터에 대한 일부 작업을 수행할 필드를 가리킵니다.

1. **유형**: 데이터의 형태를 나타내는 데 사용되는 기본 유형입니다. 주로 정의된 특성을 가진 대상의 객체나 추상적 표현으로 생각할 수 있습니다. 예를 들어, 데이터베이스에 있는 사람을 나타내는 `Person` 객체를 만들 수 있습니다. 각 개인의 특성은 `Person` 내에 필드로 정의됩니다. 개인의 이름, 나이, 직업, 주소 등 무엇이든 될 수 있습니다.

1. **특수 객체 유형**: 스키마의 작업 동작을 정의하는 유형입니다. 각 특수 객체 유형은 스키마별로 한 번씩 정의됩니다. 먼저 스키마 루트에 배치된 다음 스키마 본문에 정의됩니다. 특수 객체 유형의 각 필드는 해석기가 구현할 단일 작업을 정의합니다.

이 개념을 잘 이해하기 위해 저자와 저자가 쓴 책을 저장하는 서비스를 만든다고 가정해 보세요. 저자마다 이름이 있고 저술한 책도 여러 권 있습니다. 각 책에는 이름과 관련 저자 목록이 있습니다. 또한 책과 저자를 추가하거나 검색할 수 있는 기능도 필요합니다. 이 관계를 간단한 UML로 표현하면 다음과 같을 수 있습니다.

![\[UML diagram showing Author and Book classes with attributes and methods, linked by association.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/GraphQL-UML-1.png)


GraphQL에서 `Author` 및 `Book` 엔터티는 스키마의 서로 다른 두 가지 객체 유형을 나타냅니다.

```
type Author {
}

type Book {
}
```

`Author`는 `authorName`과 `Books`를 포함하는 반면, `Book`은 `bookName`과 `Authors`를 포함합니다. 이러한 유형은 유형 범위 내의 필드로 표시될 수 있습니다.

```
type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}
```

보는 것과 같이 유형 표현은 다이어그램과 매우 비슷합니다. 하지만 메서드의 경우 조금 더 까다로워집니다. 메서드는 몇 가지 특수 객체 유형 중 하나에 필드로 배치됩니다. 특수 객체 분류는 동작에 따라 결정됩니다. GraphQL에는 쿼리, 변형, 구독이라는 세 가지 기본 특수 객체 유형이 포함되어 있습니다. 자세한 내용은 [특수 객체](https://docs.aws.amazon.com//appsync/latest/devguide/graphql-types.html#special-object-components)를 참조하세요.

`getAuthor`와 `getBook` 둘 다 데이터를 요청하므로 다음과 같은 `Query` 특수 객체 유형에 배치됩니다.

```
type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}
```

작업은 쿼리에 연결되며, 쿼리 자체는 스키마에 연결됩니다. 스키마 루트를 추가하면 특수 객체 유형(이 경우 `Query`)이 진입점 중 하나로 정의됩니다. 다음과 같은 `schema` 키워드를 사용하여 수행할 수 있습니다.

```
schema {
  query: Query
}

type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}
```

마지막 두 메서드를 살펴보면 `addAuthor` 및 `addBook`은 데이터베이스에 데이터를 추가하고 있으므로 `Mutation` 특수 객체 유형에 정의됩니다. 그러나 [유형](https://docs.aws.amazon.com/appsync/latest/devguide/graphql-types.html#input-components) 페이지를 보면 객체를 직접 참조하는 입력은 엄밀히는 출력 유형이기 때문에 허용되지 않는다는 사실도 알 수 있습니다. 이 경우에는 `Author` 또는 `Book`을 사용할 수 없으므로 동일한 필드로 입력 유형을 만들어야 합니다. 이 예제에서는 `AuthorInput` 및 `BookInput`을 추가했는데, 둘 다 해당 유형의 동일한 필드를 수락합니다. 그런 다음 입력값을 파라미터로 사용하여 변형을 생성합니다.

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

type Author {
  authorName: String
  Books: [Book]
}

input AuthorInput {
  authorName: String
  Books: [BookInput]
}

type Book {
  bookName: String
  Authors: [Author]
}

input BookInput {
  bookName: String
  Authors: [AuthorInput]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}

type Mutation {
  addAuthor(input: [BookInput]): Author
  addBook(input: [AuthorInput]): Book
}
```

방금 수행한 단계를 다시 살펴보겠습니다.

1. 엔터티를 나타내는 `Book` 및 `Author` 유형을 사용하여 스키마를 만들었습니다.

1. 엔터티의 특성이 포함된 필드를 추가했습니다.

1. 데이터베이스에서 이 정보를 검색하는 쿼리를 추가했습니다.

1. 데이터베이스의 데이터를 조작하기 위해 변형을 추가했습니다.

1. GraphQL의 규칙을 준수하기 위해 변형의 객체 파라미터를 대체하는 입력 유형을 추가했습니다.

1. GraphQL 구현이 루트 유형 위치를 이해할 수 있도록 루트 스키마에 쿼리와 변형을 추가했습니다.

보는 것과 같이 스키마를 생성하는 프로세스는 일반적으로 데이터 모델링(특히 데이터베이스 모델링)으로부터 많은 개념을 가져옵니다. 스키마는 원본의 데이터 형태와 맞는 것으로 생각할 수 있습니다. 또한 해석기가 구현할 모델 역할도 합니다. 다음 단원에서는 다양한 AWS지원 도구 및 서비스를 사용하여 스키마를 만드는 방법을 알아봅니다.

**참고**  
다음 섹션의 예제는 실제 애플리케이션에서 실행하도록 설계된 것이 아닙니다. 직접 애플리케이션을 빌드할 수 있도록 명령을 보여 주기 위한 용도로만 제공됩니다.

## 스키마 생성
<a name="creating-schema"></a>

스키마는 라는 파일에 있습니다`schema.graphql`. AWS AppSync를 사용하면 다양한 방법을 사용하여 GraphQL APIs에 대한 새 스키마를 생성할 수 있습니다. 이 예에서는 빈 스키마와 함께 빈 API를 생성해 보겠습니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **대시보드**에서 **API 생성**을 선택합니다.

   1. **API 옵션**에서 **GraphQL API**, **처음부터 설계**, **다음**을 차례로 선택합니다.

      1. **API 이름**의 경우 미리 채워진 이름을 애플리케이션에 필요한 이름으로 변경합니다.

      1. **연락처 세부 정보**에는 API 관리자를 식별할 연락처를 입력하면 됩니다. 이 필드는 선택 사항입니다.

      1. **프라이빗 API 구성**에서 프라이빗 API 기능을 활성화할 수 있습니다. 프라이빗 API는 구성된 VPC 엔드포인트(VPCE)에서만 액세스할 수 있습니다. 자세한 내용은 [프라이빗 API](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html)를 참조하세요.

         이 예에서는 이 기능을 활성화하지 않는 것이 좋습니다. 입력 내용을 검토한 후 **다음**을 선택합니다.

   1. **GraphQL 유형 생성**에서 데이터 소스로 사용할 DynamoDB 테이블을 생성할지, 아니면 이 단계를 건너뛰고 나중에 생성할지 선택할 수 있습니다.

      이 예제에서는 **나중에 GraphQL 리소스 생성**을 선택합니다. 별도의 섹션에서 리소스를 생성할 것입니다.

   1. 입력 내용을 검토한 다음 **API 생성**을 선택합니다.

1. 특정 API의 대시보드로 이동하게 됩니다. API 이름은 대시보드 상단에 표시되므로 알아볼 수 있습니다. 그렇지 않은 경우 **사이드바**에서 **API**를 선택한 다음 **API 대시보드**에서 API를 선택하면 됩니다.

   1. API 이름 아래에 있는 **사이드바**에서 **스키마**를 선택합니다.

1. **스키마 편집기**에서 `schema.graphql` 파일을 구성할 수 있습니다. 파일이 비어 있거나 모델에서 생성된 유형으로 채워져 있을 수 있습니다. 오른쪽에는 스키마 필드에 해석기를 연결할 수 있는 **해석기** 섹션이 있습니다. 이 섹션에서는 해석기는 살펴보지 않겠습니다.

------
#### [ CLI ]

**참고**  
CLI를 사용하는 경우 서비스에서 리소스에 액세스하고 리소스를 생성할 수 있는 올바른 권한이 있어야 합니다. 서비스에 액세스해야 하는 관리자가 아닌 사용자를 위해 [최소 권한](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) 정책을 설정할 수도 있습니다. AWS AppSync 정책에 대한 자세한 내용은 [의 자격 증명 및 액세스 관리를 참조하세요 AWS AppSync](https://docs.aws.amazon.com//appsync/latest/devguide/security-iam.html).  
또한 아직 읽어보지 않은 경우 먼저 콘솔 버전을 읽어보시기 바랍니다.

1. 아직 완료하지 않았다면 AWS CLI를 [설치](https://docs.aws.amazon.com//cli/latest/userguide/cli-chap-getting-started.html)한 다음 [구성](https://docs.aws.amazon.com//cli/latest/userguide/cli-configure-quickstart.html)을 추가합니다.

1. [https://docs.aws.amazon.com/cli/latest/reference/appsync/create-graphql-api.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-graphql-api.html) 명령을 실행하여 GraphQL API 객체를 생성합니다.

   이 특정 명령에 대해 두 개의 파라미터를 입력해야 합니다.

   1. API의 `name`.

   1. `authentication-type` 또는 API에 액세스하는 데 사용되는 보안 인증 유형(IAM, OIDC 등)
**참고**  
필수로 구성해야 하지만 일반적으로 CLI 구성 값으로 기본 설정되는 `Region`과 같은 다른 파라미터도 있습니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync create-graphql-api --name testAPI123 --authentication-type API_KEY
   ```

   CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

   ```
   {
       "graphqlApi": {
           "xrayEnabled": false,
           "name": "testAPI123",
           "authenticationType": "API_KEY",
           "tags": {},
           "apiId": "abcdefghijklmnopqrstuvwxyz",
           "uris": {
               "GRAPHQL": "https://zyxwvutsrqponmlkjihgfedcba.appsync-api.us-west-2.amazonaws.com/graphql",
               "REALTIME": "wss://zyxwvutsrqponmlkjihgfedcba.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
           },
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz"
       }
   }
   ```

1. 
**참고**  
기존 스키마를 가져와 base-64 blob을 사용하여 AWS AppSync 서비스에 업로드하는 선택적 명령입니다. 이 예제에서는 이 명령을 사용하지 않을 것입니다.

   [https://docs.aws.amazon.com/cli/latest/reference/appsync/start-schema-creation.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/start-schema-creation.html) 명령을 실행합니다.

   이 특정 명령에 대해 두 개의 파라미터를 입력해야 합니다.

   1. 이전 단계의 `api-id`입니다.

   1. `definition` 스키마는 base-64로 인코딩된 바이너리 blob입니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
    aws appsync start-schema-creation --api-id abcdefghijklmnopqrstuvwxyz --definition "aa1111aa-123b-2bb2-c321-12hgg76cc33v"
   ```

   출력이 반환됩니다.

   ```
   {
       "status": "PROCESSING"
   }
   ```

   이 명령은 처리 후 최종 출력을 반환하지 않습니다. 결과를 보려면 별도의 명령인 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/get-schema-creation-status.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/get-schema-creation-status.html)를 사용해야 합니다. 참고로 이 두 명령은 비동기식이므로 스키마를 생성하는 중에도 출력 상태를 확인할 수 있습니다.

------
#### [ CDK ]

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/home.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
아래 나열된 단계는 특정 리소스를 추가하는 데 사용되는 스니펫의 일반적인 예시만 보여줍니다. 프로덕션 코드에서는 이 예시가 올바르게 작동하는 솔루션이 **아닙니다**. 또한 이미 작동하는 앱을 가지고 있는 것으로 가정합니다.

1. CDK의 시작점은 약간 다릅니다. 이상적으로는 `schema.graphql` 파일이 이미 생성되어 있어야 합니다. `.graphql` 파일 확장자가 있는 새 파일을 생성하기만 하면 됩니다. 빈 파일이어도 괜찮습니다.

1. 대개는 사용 중인 서비스에 가져오기 지침을 추가해야 할 수 있습니다. 예를 들면 다음 형식을 따를 수 있습니다.

   ```
   import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
   import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
   ```

   GraphQL API를 추가하려면 스택 파일이 AWS AppSync 서비스를 가져와야 합니다.

   ```
   import * as appsync from 'aws-cdk-lib/aws-appsync';
   ```
**참고**  
즉, `appsync` 키워드로 전체 서비스를 가져오게 됩니다. 앱에서 이를 사용하기 위해 AWS AppSync 구문은 형식을 사용합니다`appsync.construct_name`. 예를 들어, GraphQL API를 만들고 싶다면 `new appsync.GraphqlApi(args_go_here)`를 사용할 수 있습니다. 다음 단계에서는 이 과정을 설명합니다.

1. 가장 기본적인 GraphQL API에는 API의 `name` 및 `schema` 경로가 포함됩니다.

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     name: 'name_of_API_in_console',
     schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema_name.graphql')),
   });
   ```
**참고**  
이 스니펫이 어떤 역할을 하는지 살펴보겠습니다. `api`의 범위 내에서 `appsync.GraphqlApi(scope: Construct, id: string, props: GraphqlApiProps)`를 호출하여 새로운 GraphQL API를 만들고 있습니다. 범위는 `this`이며, 현재 객체를 참조합니다. id는 *API\$1ID*이며, 생성 CloudFormation 시에서 GraphQL API의 리소스 이름이 됩니다. `GraphqlApiProps`에는 GraphQL API의 `name` 및 `schema`가 포함되어 있습니다. `schema`는 `.graphql` 파일(*schema\$1name.graphql*)의 절대 경로(`__dirname`)를 검색하여 스키마(`SchemaFile.fromAsset`)를 생성합니다. 실제 시나리오에서는 스키마 파일이 CDK 앱 내에 있을 수 있습니다.  
GraphQL API에서 변경한 내용을 사용하려면 앱을 재배포해야 합니다.

------

## 스키마에 유형 추가
<a name="adding-schema-types"></a>

이제 스키마를 추가했으니 입력 유형과 출력 유형을 모두 추가할 수 있습니다. 참고로 여기에 있는 유형은 실제 코드에서 사용해서는 안 됩니다. 프로세스 이해를 돕기 위한 예시일 뿐입니다.

먼저 객체 유형을 생성하겠습니다. 실제 코드에서는 이러한 유형으로 시작할 필요가 없습니다. GraphQL의 규칙과 구문만 따르면 언제든지 원하는 유형을 만들 수 있습니다.

**참고**  
다음 몇 개의 섹션에서 **스키마 편집기**를 사용할 예정이니 계속 열어 두세요.

------
#### [ Console ]
+ 유형 이름과 함께 `type` 키워드를 사용하여 객체 유형을 생성할 수 있습니다.

  ```
  type Type_Name_Goes_Here {}
  ```

  유형의 범위 내에 객체의 특성을 나타내는 필드를 추가할 수 있습니다.

  ```
  type Type_Name_Goes_Here {
    # Add fields here
  }
  ```

  다음은 그 예입니다.

  ```
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  ```
**참고**  
이 단계에서는 필수 `id` 필드는 `ID`로, `title` 필드는 `String`으로, `date` 필드는 `AWSDateTime`으로 저장되는 일반 객체 유형을 추가했습니다. 유형 및 필드의 목록과 그 역할을 보려면 [스키마](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)를 참조하세요. 스칼라 목록과 그 역할을 보려면 [유형 참조](https://docs.aws.amazon.com/appsync/latest/devguide/type-reference.html)를 참조하세요.

------
#### [ CLI ]

**참고**  
아직 읽어보지 않은 경우 먼저 콘솔 버전을 읽어보시기 바랍니다.
+ [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 명령을 실행하여 객체 유형을 만들 수 있습니다.

  이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

  1. API의 `api-id`.

  1. `definition` 또는 유형의 내용. 콘솔 예제에서는 다음과 같았습니다.

     ```
     type Obj_Type_1 {
       id: ID!
       title: String
       date: AWSDateTime
     }
     ```

  1. 입력의 `format`. 이 예제에서는 `SDL`을 사용합니다.

  예를 들어 명령은 다음과 같을 수 있습니다.

  ```
  aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Obj_Type_1{id: ID! title: String date: AWSDateTime}" --format SDL
  ```

  CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

  ```
  {
      "type": {
          "definition": "type Obj_Type_1{id: ID! title: String date: AWSDateTime}",
          "name": "Obj_Type_1",
          "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Obj_Type_1",
          "format": "SDL"
      }
  }
  ```
**참고**  
이 단계에서는 필수 `id` 필드는 `ID`로, `title` 필드는 `String`으로, `date` 필드는 `AWSDateTime`으로 저장되는 일반 객체 유형을 추가했습니다. 유형 및 필드의 목록과 그 역할을 보려면 [스키마](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)를 참조하세요. 스칼라 목록과 그 역할을 보려면 [유형 참조](https://docs.aws.amazon.com/appsync/latest/devguide/type-reference.html)를 참조하세요.  
추가로 설명하자면, 정의를 직접 입력하는 것은 크기가 작은 유형에서는 효과적이지만, 크기가 크거나 여러 개인 유형에는 적합하지 않다는 사실을 확인하셨을 수 있습니다. `.graphql` 파일에 모든 유형을 추가한 다음 [입력으로 전달](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-file.html)하도록 선택할 수 있습니다.

------
#### [ CDK ]

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/home.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
아래 나열된 단계는 특정 리소스를 추가하는 데 사용되는 스니펫의 일반적인 예시만 보여줍니다. 프로덕션 코드에서는 이 예시가 올바르게 작동하는 솔루션이 **아닙니다**. 또한 이미 작동하는 앱을 가지고 있는 것으로 가정합니다.

유형을 추가하려면 `.graphql` 파일에 추가해야 합니다. 예를 들어 콘솔 예시에서는 다음과 같았습니다.

```
type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}
```

다른 파일처럼 스키마에 유형을 직접 추가할 수 있습니다.

**참고**  
GraphQL API에서 변경한 내용을 사용하려면 앱을 재배포해야 합니다.

------

[객체 유형에](https://graphql.org/learn/schema/#object-types-and-fields)는 문자열 및 정수와 같은 [스칼라 유형](https://graphql.org/learn/schema/#scalar-types)인 필드가 있습니다. AWS AppSync를 사용하면 기본 GraphQL 스칼라 `AWSDateTime` 외에도와 같은 향상된 스칼라 유형을 사용할 수도 있습니다. 또한 느낌표로 끝나는 모든 필드는 필수 필드입니다.

특히 `ID` 스칼라 유형은 `String` 또는 `Int`인 고유한 식별자입니다. 자동 할당을 위해 해석기 코드에서 이러한 유형을 제어할 수 있습니다.

`Query`와 같은 특수 객체 유형과 위의 예와 같은 '일반' 객체 유형 간에는 모두 `type` 키워드를 사용하고 객체로 간주된다는 점에서 유사점이 있습니다. 하지만 특수 객체 유형(`Query`, `Mutation`, `Subscription`)의 경우 API의 진입점으로 노출되므로 동작은 크게 다릅니다. 또한 데이터보다는 작업의 형태를 잡는 데 더 중점을 둡니다. 자세한 내용은 [쿼리 및 변형 유형](https://graphql.org/learn/schema/#the-query-and-mutation-types)을 참조하세요.

특수 객체 유형의 경우 다음 단계는 형상화된 데이터에 대한 작업을 수행하기 위해 하나 이상의 유형을 추가하는 것일 수 있습니다. 실제 시나리오에서 모든 GraphQL 스키마에는 데이터 요청을 위한 루트 쿼리 유형이 반드시 있어야 합니다. 쿼리는 GraphQL 서버의 진입점(또는 엔드포인트) 중 하나로 생각할 수 있습니다. 쿼리를 예로 추가해 보겠습니다.

------
#### [ Console ]
+ 쿼리를 만들려면 다른 유형과 마찬가지로 스키마 파일에 추가하기만 하면 됩니다. 쿼리에는 다음과 같이 루트에 `Query` 유형 및 항목이 필요합니다.

  ```
  schema {
    query: Name_of_Query
  }
  
  type Name_of_Query {
    # Add field operation here
  }
  ```

  참고로 프로덕션 환경에서는 *Name\$1of\$1Query*를 대부분의 경우 단순히 `Query`라고 합니다. 이 값을 유지하는 것이 좋습니다. 쿼리 유형 내에서 필드를 추가할 수 있습니다. 각 필드는 요청에서 작업을 수행합니다. 따라서 전부는 아니더라도 대부분의 필드가 해석기에 연결됩니다. 하지만 이 섹션에서는 신경 쓰지 않습니다. 필드 작업의 형식과 관련해서는 다음과 같을 수 있습니다.

  ```
  Name_of_Query(params): Return_Type # version with params
  Name_of_Query: Return_Type # version without params
  ```

  다음은 그 예입니다.

  ```
  schema {
    query: Query
  }
  
  type Query {
    getObj: [Obj_Type_1]
  }
  
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  ```
**참고**  
이 단계에서는 `Query` 유형을 추가하고 `schema` 루트에 정의했습니다. `Query` 유형은 `Obj_Type_1` 객체 목록을 반환하는 `getObj` 필드를 정의했습니다. 참고로 `Obj_Type_1`은 이전 단계의 객체입니다. 프로덕션 코드에서는 일반적으로 `Obj_Type_1`과 같은 객체로 형태가 지정된 데이터를 사용하여 필드 작업을 수행하게 됩니다. 또한 `getObj`와 같은 필드에는 일반적으로 비즈니스 로직을 수행하는 해석기가 있습니다. 이 내용은 다른 섹션에서 다룰 예정입니다.  
참고로는 내보내기 중에 스키마 루트를 AWS AppSync 자동으로 추가하므로 기술적으로 스키마에 직접 추가할 필요가 없습니다. 본 서비스는 중복 스키마를 자동으로 처리합니다. 이 내용은 여기에 모범 사례로 추가하겠습니다.

------
#### [ CLI ]

**참고**  
아직 읽어보지 않은 경우 먼저 콘솔 버전을 읽어보시기 바랍니다.

1. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 명령을 실행하여 `query` 정의가 있는 `schema` 루트를 생성합니다.

   이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

   1. API의 `api-id`.

   1. `definition` 또는 유형의 내용. 콘솔 예제에서는 다음과 같았습니다.

      ```
      schema {
        query: Query
      }
      ```

   1. 입력의 `format`. 이 예제에서는 `SDL`을 사용합니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "schema {query: Query}" --format SDL
   ```

   CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

   ```
   {
       "type": {
           "definition": "schema {query: Query}",
           "name": "schema",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```
**참고**  
`create-type` 명령에 내용을 올바르게 입력하지 않은 경우 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html) 명령을 실행하여 스키마 루트(또는 스키마의 모든 유형)를 업데이트할 수 있습니다. 이 예에서는 `subscription` 정의를 포함하도록 스키마 루트를 일시적으로 변경해 보겠습니다.  
이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.  
API의 `api-id`.
유형의 `type-name`. 콘솔 예제에서는 `schema`였습니다.
`definition` 또는 유형의 내용. 콘솔 예제에서는 다음과 같았습니다.  

      ```
      schema {
        query: Query
      }
      ```
`subscription`을 추가한 후의 스키마는 다음과 같습니다.  

      ```
      schema {
        query: Query
        subscription: Subscription
      }
      ```
입력의 `format`. 이 예제에서는 `SDL`을 사용합니다.
예를 들어 명령은 다음과 같을 수 있습니다.  

   ```
   aws appsync update-type --api-id abcdefghijklmnopqrstuvwxyz --type-name schema --definition "schema {query: Query subscription: Subscription}" --format SDL
   ```
CLI에서 출력이 반환됩니다. 다음은 그 예입니다.  

   ```
   {
       "type": {
           "definition": "schema {query: Query subscription: Subscription}",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```
이 예제에서는 미리 형식이 지정된 파일을 추가해도 여전히 작동합니다.

1. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 명령을 실행하여 `Query` 유형을 생성합니다.

   이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

   1. API의 `api-id`.

   1. `definition` 또는 유형의 내용. 콘솔 예제에서는 다음과 같았습니다.

      ```
      type Query {
        getObj: [Obj_Type_1]
      }
      ```

   1. 입력의 `format`. 이 예제에서는 `SDL`을 사용합니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Query {getObj: [Obj_Type_1]}" --format SDL
   ```

   CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

   ```
   {
       "type": {
           "definition": "Query {getObj: [Obj_Type_1]}",
           "name": "Query",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Query",
           "format": "SDL"
       }
   }
   ```
**참고**  
이 단계에서는 `Query` 유형을 추가하고 `schema` 루트에 정의했습니다. `Query` 유형은 `Obj_Type_1` 객체 목록을 반환한 `getObj` 필드를 정의했습니다.  
`schema` 루트 코드 `query: Query`에서 `query:` 부분은 쿼리가 스키마에 정의되었음을 나타내고 `Query` 부분은 실제 특수 객체 이름을 나타냅니다.

------
#### [ CDK ]

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/home.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
아래 나열된 단계는 특정 리소스를 추가하는 데 사용되는 스니펫의 일반적인 예시만 보여줍니다. 프로덕션 코드에서는 이 예시가 올바르게 작동하는 솔루션이 **아닙니다**. 또한 이미 작동하는 앱을 가지고 있는 것으로 가정합니다.

쿼리와 스키마 루트를 `.graphql` 파일에 추가해야 합니다. 예제에서는 아래와 비슷했지만, 실제 스키마 코드로 바꿔야 할 수 있습니다.

```
schema {
  query: Query
}

type Query {
  getObj: [Obj_Type_1]
}

type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}
```

다른 파일처럼 스키마에 유형을 직접 추가할 수 있습니다.

**참고**  
스키마 루트 업데이트는 선택 사항입니다. 이 예제에 모범 사례로 추가했습니다.  
GraphQL API에서 변경한 내용을 사용하려면 앱을 재배포해야 합니다.

------

이제 객체와 특수 객체(쿼리)를 모두 생성하는 예제를 살펴보았습니다. 또한 이러한 객체를 상호 연결하여 데이터와 작업을 설명하는 방법도 살펴보았습니다. 데이터 설명과 하나 이상의 쿼리만 포함된 스키마를 사용할 수 있습니다. 하지만 데이터 원본에 데이터를 추가하는 또 다른 작업을 추가하려고 합니다. 데이터를 수정하는 `Mutation`이라는 또 하나의 특수 객체 유형을 추가할 것입니다.

------
#### [ Console ]
+ 변형은 `Mutation`이라고 부르겠습니다. `Query`와 마찬가지로, `Mutation` 내부의 필드 작업은 작업을 설명하고 해석기에 연결됩니다. 또한 특수 객체 유형이기 때문에 `schema` 루트에 정의해야 합니다. 다음은 변형의 예입니다.

  ```
  schema {
    mutation: Name_of_Mutation
  }
  
  type Name_of_Mutation {
    # Add field operation here
  }
  ```

  일반적인 변형은 쿼리처럼 루트에 나열됩니다. 변형은 이름과 함께 `type` 키워드를 사용하여 정의됩니다. *Name\$1of\$1Mutation*은 일반적으로 `Mutation`으로 불리므로 그대로 유지하는 것이 좋습니다. 또한 각 필드는 작업을 수행합니다. 필드 작업의 형식과 관련해서는 다음과 같을 수 있습니다.

  ```
  Name_of_Mutation(params): Return_Type # version with params
  Name_of_Mutation: Return_Type # version without params
  ```

  다음은 그 예입니다.

  ```
  schema {
    query: Query
    mutation: Mutation
  }
  
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  
  type Query {
    getObj: [Obj_Type_1]
  }
  
  type Mutation {
    addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
  }
  ```
**참고**  
이 단계에서는 `addObj` 필드가 있는 `Mutation` 유형을 추가했습니다. 이 필드의 기능을 요약해 보겠습니다.  

  ```
  addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
  ```
`addObj`는 `Obj_Type_1` 객체를 사용하여 작업을 수행합니다. 필드로 인해 분명히 알 수도 있지만, `: Obj_Type_1` 반환 유형에서도 구문을 통해 이를 증명할 수 있습니다. `addObj` 내부에서는 `Obj_Type_1` 객체의 `id`, `title`, `date` 필드를 파라미터로 수용합니다. 보는 것과 같이 메서드 선언과 매우 흡사합니다. 하지만 메서드의 동작에 대해서는 아직 설명하지 않았습니다. 앞서 설명했듯이 스키마는 데이터와 작업의 내용을 정의하는 용도로만 사용되며 작동 방식을 정의하는 용도로는 사용할 수 없습니다. 실제 비즈니스 로직을 구현하는 방법은 나중에 첫 번째 해석기를 만들 때 다루게 될 것입니다.  
스키마 작업을 완료하면 `schema.graphql` 파일로 내보낼 수 있는 옵션이 있습니다. **스키마 편집기**에서 **스키마 내보내기**를 선택하여 지원되는 형식으로 파일을 다운로드할 수 있습니다.  
참고로는 내보내기 중에 스키마 루트를 AWS AppSync 자동으로 추가하므로 기술적으로 스키마에 직접 추가할 필요가 없습니다. 본 서비스는 중복 스키마를 자동으로 처리합니다. 이 내용은 여기에 모범 사례로 추가하겠습니다.

------
#### [ CLI ]

**참고**  
아직 읽어보지 않은 경우 먼저 콘솔 버전을 읽어보시기 바랍니다.

1. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html) 명령을 실행하여 루트 스키마를 업데이트하세요.

   이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

   1. API의 `api-id`.

   1. 유형의 `type-name`. 콘솔 예제에서는 `schema`였습니다.

   1. `definition` 또는 유형의 내용. 콘솔 예제에서는 다음과 같았습니다.

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

   1. 입력의 `format`. 이 예제에서는 `SDL`을 사용합니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync update-type --api-id abcdefghijklmnopqrstuvwxyz --type-name schema --definition "schema {query: Query mutation: Mutation}" --format SDL
   ```

   CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

   ```
   {
       "type": {
           "definition": "schema {query: Query mutation: Mutation}",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```

1. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 명령을 실행하여 `Mutation` 유형을 생성합니다.

   이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

   1. API의 `api-id`.

   1. `definition` 또는 유형의 내용. 콘솔 예제에서는 다음과 같았습니다.

      ```
      type Mutation {
        addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
      }
      ```

   1. 입력의 `format`. 이 예제에서는 `SDL`을 사용합니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Mutation {addObj(id: ID! title: String date: AWSDateTime): Obj_Type_1}" --format SDL
   ```

   CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

   ```
   {
       "type": {
           "definition": "type Mutation {addObj(id: ID! title: String date: AWSDateTime): Obj_Type_1}",
           "name": "Mutation",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation",
           "format": "SDL"
       }
   }
   ```

------
#### [ CDK ]

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/home.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
아래 나열된 단계는 특정 리소스를 추가하는 데 사용되는 스니펫의 일반적인 예시만 보여줍니다. 프로덕션 코드에서는 이 예시가 올바르게 작동하는 솔루션이 **아닙니다**. 또한 이미 작동하는 앱을 가지고 있는 것으로 가정합니다.

쿼리와 스키마 루트를 `.graphql` 파일에 추가해야 합니다. 예제에서는 아래와 비슷했지만, 실제 스키마 코드로 바꿔야 할 수 있습니다.

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

type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}

type Query {
  getObj: [Obj_Type_1]
}

type Mutation {
  addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
}
```

**참고**  
스키마 루트 업데이트는 선택 사항입니다. 이 예제에 모범 사례로 추가했습니다.  
GraphQL API에서 변경한 내용을 사용하려면 앱을 재배포해야 합니다.

------

## 선택적 고려 사항 - 열거형을 상태로 사용
<a name="optional-consideration-enums"></a>

이제 기본 스키마를 만드는 방법을 알게 되었습니다. 그러나 스키마의 기능을 향상하기 위해 추가할 수 있는 많은 항목이 있습니다. 애플리케이션에서 흔히 볼 수 있는 방법 중 하나는 열거형을 상태로 사용하는 방법입니다. 열거형을 사용하여 호출 시 값 집합에서 특정 값을 선택하도록 할 수 있습니다. 이 옵션은 시간이 오래 지나도 크게 변하지 않을 것임을 알고 있는 경우에 유용합니다. 가정해 보자면, 응답에 상태 코드나 문자열을 반환하는 열거형을 추가할 수도 있습니다.

예를 들어 백엔드에 사용자의 게시물 데이터를 저장하는 소셜 미디어 앱을 만들고 있다고 가정해 보겠습니다. 스키마에는 개별 게시물의 데이터를 나타내는 `Post` 유형이 포함되어 있습니다.

```
type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}
```

`Post`에는 고유한 `id`, 게시물 `title`, 게시한 `date` 및 앱에서 처리되는 게시물 상태를 나타내는 `PostStatus`라는 열거형이 포함됩니다. 작업을 위해 모든 게시물 데이터를 반환하는 쿼리를 만들겠습니다.

```
type Query {
  getPosts: [Post]
}
```

또한 데이터 원본에 게시물을 추가하는 변형도 생성할 것입니다.

```
type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}
```

스키마를 보면 `PostStatus` 열거형에 여러 상태가 있는 것을 볼 수 있습니다. `success`(게시물 처리 완료), `pending`(게시물 처리 중), `error`(게시물을 처리할 수 없음)의 세 가지 기본 상태가 필요할 수 있습니다. 다음과 같이 열거형을 추가할 수 있습니다.

```
enum PostStatus {
  success
  pending
  error
}
```

전체 스키마는 다음과 같을 수 있습니다.

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

type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}

type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}

type Query {
  getPosts: [Post]
}

enum PostStatus {  
  success
  pending
  error
}
```

사용자가 애플리케이션에 `Post`를 추가하면 해당 데이터를 처리하기 위해 `addPost` 작업이 호출됩니다. `addPost`에 연결된 해석기가 데이터를 처리하는 동안 `poststatus`를 작업의 상태로 계속 업데이트합니다. 쿼리 시 `Post`에는 데이터의 최종 상태가 포함됩니다. 여기서는 스키마에서 데이터가 작동하는 방식에 대해서만 설명하고 있다는 점을 기억하세요. 요청을 이행하기 위해 데이터를 처리하는 실제 비즈니스 로직을 구현하는 해석기의 구현에 대해서는 많은 사항을 가정합니다.

## 선택적 고려 사항 - 구독
<a name="optional-consideration-subscriptions"></a>

 AWS AppSync의 구독은 변형에 대한 응답으로 호출됩니다. 스키마의 `Subscription` 지시문과 `@aws_subscribe()` 유형을 사용하여 이 호출을 구성하면 하나 이상의 구독을 호출하는 변형을 지정할 수 있습니다. 구독 구성에 대한 자세한 내용은 [실시간 데이터](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html)를 참조하세요.

## 선택적 고려 사항 - 관계 및 페이지 매김
<a name="optional-consideration-relations-and-pagination"></a>

DynamoDB 테이블에 백만 개의 `Posts`가 저장되어 있고 그 데이터 중 일부를 반환하려고 한다고 가정해 보겠습니다. 그러나 위에 제공된 예제 쿼리는 모든 게시물만 반환합니다. 요청을 할 때마다 모든 게시물을 가져오고 싶지는 않을 수 있습니다. 대신 데이터에 [페이지를 지정](https://graphql.org/learn/pagination/)할 수 있습니다. 스키마를 다음과 같이 변경합니다.
+ `getPosts` 필드에 `nextToken`(반복자) 및 `limit`(반복 제한)이라는 두 개의 입력 인수를 추가합니다.
+ `Posts`(`Post` 객체 목록 검색) 및 `nextToken`(반복자) 필드를 포함하는 새 `PostIterator` 유형을 추가합니다.
+ `Post` 객체 목록이 아닌 `PostIterator`를 반환하도록 `getPosts`를 변경합니다.

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

type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}

type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}

type Query {
  getPosts(limit: Int, nextToken: String): PostIterator
}

enum PostStatus {
  success
  pending
  error
}

type PostIterator {
  posts: [Post]
  nextToken: String
}
```

`PostIterator` 유형을 사용하면 `Post` 객체 목록의 일부와 다음 부분을 가져오기 위해 `nextToken`을 반환할 수 있습니다. `PostIterator` 내부에는 페이지 매김 토큰(`nextToken`)과 함께 반환되는 `Post` 항목(`[Post]`)의 목록이 있습니다. AWS AppSync에서는 해석기를 통해 Amazon DynamoDB에 연결되고 암호화된 토큰으로 자동으로 생성됩니다. 이 매핑 템플릿은 `limit` 인수의 값을 `maxResults` 파라미터로 변환하고 `nextToken` 인수의 값을 `exclusiveStartKey` 파라미터로 변환합니다. AWS AppSync 콘솔의 예제 또는 기본 제공 템플릿 샘플은 [해석기 참조(JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html)를 참조하세요.

# AWS AppSync에서 데이터 소스 연결
<a name="attaching-a-data-source"></a>

데이터 소스는 GraphQL APIs가 상호 작용할 수 있는 AWS 계정의 리소스입니다. AWS AppSync는 Amazon DynamoDB AWS Lambda, 관계형 데이터베이스(Amazon Aurora Serverless), Amazon OpenSearch Service 및 HTTP 엔드포인트와 같은 다양한 데이터 소스를 지원합니다. AWS AppSync API는 여러 데이터 소스와 상호 작용하도록 구성하여 단일 위치에서 데이터를 집계할 수 있습니다. AWS AppSync는 계정의 기존 AWS 리소스를 사용하거나 스키마 정의에서 사용자를 대신하여 DynamoDB 테이블을 프로비저닝할 수 있습니다.

다음 섹션에서는 GraphQL API에 데이터 원본을 연결하는 방법을 알아봅니다.

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

이제 AWS AppSync 콘솔에서 스키마를 생성했으므로 여기에 데이터 소스를 연결할 수 있습니다. API를 처음으로 만들 때 사전 정의된 스키마를 생성하는 동안 Amazon DynamoDB 테이블을 프로비저닝하는 옵션이 있습니다. 그러나 이 섹션에서는 이 옵션에 대해 다루지 않습니다. 이에 대한 예는 [스키마 시작](https://docs.aws.amazon.com//appsync/latest/devguide/schema-launch-start.html) 섹션에서 확인할 수 있습니다.

대신 AWS AppSync가 지원하는 모든 데이터 소스를 살펴보겠습니다. 애플리케이션에 적합한 솔루션을 선택할 때는 여러 가지 요소를 고려하게 됩니다. 아래 섹션에서는 각 데이터 원본에 대한 몇 가지 추가 컨텍스트를 제공합니다. 데이터 원본에 대한 일반 정보는 [데이터 원본](https://docs.aws.amazon.com/appsync/latest/devguide/data-source-components.html)을 참조하세요.

### Amazon DynamoDB
<a name="data-source-type-ddb"></a>

Amazon DynamoDB는 확장 가능한 애플리케이션을 위한 AWS주요 스토리지 솔루션 중 하나입니다. DynamoDB의 핵심 구성 요소는 단순한 데이터 모음인 **테이블**입니다. 일반적으로 `Book` 또는 `Author` 등의 엔터티를 기반으로 테이블을 만들게 됩니다. 테이블 엔트리 정보는 각 엔트리에 고유한 필드 그룹인 **항목**으로 저장됩니다. 전체 항목은 데이터베이스의 행 및 레코드를 나타냅니다. 예를 들어, `Book` 엔트리의 항목에는 해당 값과 함께 `title` 및 `author`이(가) 포함될 수 있습니다. `title` 및 `author` 등의 개별 필드를 **특성**이라고 하며, 이는 관계형 데이터베이스의 열 값과 유사합니다.

추측할 수 있듯이 테이블은 애플리케이션의 데이터를 저장하는 데 사용됩니다.를 AWS AppSync 사용하면 DynamoDB 테이블을 GraphQL API에 연결하여 데이터를 조작할 수 있습니다. 프런트엔드 웹 및 모바일 블로그에서 이 [사용 사례](https://aws.amazon.com/blogs/mobile/new-real-time-multi-group-app-with-aws-amplify-graphql-build-a-twitter-community-clone/)를 확인하세요.** 이 애플리케이션을 통해 사용자는 소셜 미디어 앱에 가입할 수 있습니다. 사용자는 그룹에 가입하고 그룹에 가입한 다른 사용자에게 브로드캐스트되는 게시물을 업로드할 수 있습니다. 해당 애플리케이션은 사용자, 게시물 및 사용자 그룹 정보를 DynamoDB에 저장합니다. GraphQL API(관리형 AWS AppSync)는 DynamoDB 테이블과 인터페이스합니다. 사용자가 시스템에서 변경하는 내용이 프런트엔드에 반영되면 GraphQL API는 이러한 변경 사항을 검색하여 다른 사용자에게 실시간으로 브로드캐스트합니다.

### AWS Lambda
<a name="data-source-type-lam"></a>

Lambda는 이벤트에 대한 응답으로 코드를 실행하는 데 필요한 리소스를 자동으로 빌드하는 이벤트 기반 서비스입니다. Lambda는 리소스를 실행하기 위한 코드, 종속성 및 구성을 포함하는 그룹 문인 **함수**를 사용합니다. 함수는 함수를 간접적으로 호출하는 활동 그룹인 **트리거**를 감지하면 자동으로 실행됩니다. 트리거는 API 호출을 수행하는 애플리케이션, 리소스를 실행하는 계정의 AWS 서비스 등일 수 있습니다. 함수가 트리거되면 수정할 데이터가 포함된 JSON 문서인 **이벤트**를 처리합니다.

Lambda는 코드를 실행하는 데 적합하며, 실행을 위해 리소스를 프로비저닝할 필요가 없습니다. 프런트엔드 웹 및 모바일 블로그에서 이 [사용 사례](https://aws.amazon.com/blogs/mobile/building-a-graphql-api-with-java-and-aws-lambda/)를 확인하세요.** 이 사용 사례는 DynamoDB 섹션에 소개된 사용 사례와 약간 비슷합니다. 이 애플리케이션에서 GraphQL API는 게시물 추가(변형) 및 해당 데이터 가져오기(쿼리)와 같은 작업을 정의하는 역할을 합니다. 작업의 기능(예: `getPost ( id: String ! ) : Post`, `getPostsByAuthor ( author: String ! ) : [ Post ]`)을 구현하기 위해 Lambda 함수를 사용하여 인바운드 요청을 처리합니다. *옵션 2:Lambda 해석기를 AWS AppSync 사용하면* AWS AppSync 서비스를 사용하여 스키마를 유지하고 Lambda 데이터 소스를 작업 중 하나에 연결합니다. 작업이 호출되면 Lambda는 Amazon RDS 프록시와 상호 작용하여 데이터베이스에서 비즈니스 로직을 수행합니다.

### Amazon RDS
<a name="data-source-type-RDS"></a>

Amazon RDS를 사용하면 관계형 데이터베이스를 빠르게 빌드하고 구성할 수 있습니다. Amazon RDS에서는 클라우드의 격리된 데이터베이스 환경으로 사용할 일반 **데이터베이스 인스턴스**를 만들게 됩니다. 이 인스턴스에서는 실제 RDBMS 소프트웨어(PostgreSQL, MySQL 등)인 **DB 엔진**을 사용합니다. 이 서비스는 AWS인프라, 패치 및 암호화와 같은 보안 서비스, 배포에 대한 관리 비용 절감을 통해 확장성을 제공하여 대부분의 백엔드 작업을 오프로드합니다.

Lambda 섹션에서 동일한 [사용 사례](https://aws.amazon.com/blogs/mobile/building-a-graphql-api-with-java-and-aws-lambda/)를 확인하세요. *옵션 3:Amazon RDS 해석기를 AWS AppSync 사용할* 때 표시되는 또 다른 옵션은의 GraphQL API를 Amazon RDS AWS AppSync 에 직접 연결하는 것입니다. 이 서비스는 [데이터 API를](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) 사용하여 데이터베이스를 GraphQL API와 연결합니다. 해석기는 필드(일반적으로 쿼리, 변형 또는 구독)에 연결되며 데이터베이스에 액세스하는 데 필요한 SQL 문을 구현합니다. 클라이언트가 필드를 호출하는 요청을 보내면 해석기는 문을 실행하고 응답을 반환합니다.

### Amazon EventBridge
<a name="data-source-type-eventbridge"></a>

EventBridge에서는 연결한 서비스 또는 애플리케이션(**이벤트 소스**)으로부터 이벤트를 수신하고 정해진 규칙에 따라 이벤트를 처리하는 파이프라인인 **이벤트 버스**를 만들게 됩니다. **이벤트**는 실행 환경의 상태가 일부 변하는 것을 의미하고, **규칙**은 이벤트에 대한 필터 집합입니다. 규칙은 **이벤트 패턴** 또는 이벤트 상태 변화의 메타데이터(ID, 리전, 계정 번호, ARN 등)를 따릅니다. 이벤트가 이벤트 패턴과 매칭되면 EventBridge는 파이프라인을 통해 대상 서비스(**대상**)로 이벤트를 보내고 규칙에 지정된 작업을 트리거합니다.

EventBridge는 상태가 변경되는 작업을 일부 다른 서비스로 라우팅하는 데 적합합니다. 프런트엔드 웹 및 모바일 블로그에서 이 [사용 사례](https://aws.amazon.com/blogs/mobile/appsync-eventbridge/)를 확인하세요.** 이 예시는 여러 팀이 서로 다른 서비스를 유지 관리하는 전자 상거래 솔루션을 보여줍니다. 이러한 서비스 중 하나는 프런트엔드에서 배송의 단계(주문 생성, 진행 중, 발송됨, 배송됨 등)마다 고객에게 주문 업데이트를 제공합니다. 그러나 별도의 백엔드 팀에서 주문 시스템 데이터를 유지 관리하기 때문에 이 서비스를 관리하는 프런트엔드 팀은 주문 시스템 데이터에 직접 액세스할 수 없습니다. 백엔드 팀의 주문 시스템은 블랙박스라고도 불릴 정도로 데이터를 구조화하는 방식에 대한 정보를 얻기가 어렵습니다. 하지만 백엔드 팀은 EventBridge에서 관리하는 이벤트 버스를 통해 주문 데이터를 게시하는 시스템을 구축했습니다. 이벤트 버스에서 오는 데이터에 액세스하여 프런트엔드로 라우팅하기 위해 프런트엔드 팀은 GraphQL API를 가리키는 새 대상을 생성했습니다 AWS AppSync. 또한 주문 업데이트와 관련된 데이터만 전송하는 규칙도 만들었습니다. 업데이트가 이루어지면 이벤트 버스의 데이터가 GraphQL API로 전송됩니다. API의 스키마는 데이터를 처리한 후 이를 프런트엔드로 전달합니다.

### 데이터 원본 없음
<a name="data-source-type-none"></a>

데이터 원본을 사용할 계획이 없다면 `none`으로 설정할 수 있습니다. 명시적으로는 여전히 데이터 소스로 분류되지만 `none` 데이터 원본은 저장 매체가 아닙니다. 일반적으로 해석기는 요청을 처리하기 위해 특정 시점에 하나 이상의 데이터 원본을 간접적으로 호출합니다. 그러나 데이터 원본을 조작할 필요가 없는 경우도 있습니다. 데이터 원본을 `none`(으)로 설정하면 요청이 실행되고 데이터 간접 호출 단계를 건너뛴 다음 응답이 실행됩니다.

EventBridge 섹션에서 동일한 [사용 사례](https://aws.amazon.com/blogs/mobile/appsync-eventbridge/)를 확인하세요. 스키마에서 변형은 상태 업데이트를 처리한 다음 구독자에게 전송합니다. 해석기의 작동 방식을 생각해보면, 보통 한 번 이상의 데이터 원본 간접 호출이 있습니다. 그러나 이 시나리오의 데이터는 이미 이벤트 버스에 의해 자동으로 전송되었습니다. 즉, 변형이 데이터 원본 간접 호출을 수행할 필요가 없으며, 주문 상태를 로컬에서 간단히 처리할 수 있습니다. 변형은 `none`(으)로 설정되며, 이 경우 데이터 원본 간접 호출 없이 패스스루 값으로 작동합니다. 그러면 데이터가 스키마에 채워지고 구독자에게 전송됩니다.

### OpenSearch
<a name="data-source-type-opensearch"></a>

Amazon OpenSearch Service는 전체 텍스트 검색, 데이터 시각화 및 로깅을 구현하는 도구 모음입니다. 이 서비스를 사용하여 업로드한 구조화된 데이터를 쿼리할 수 있습니다.

이 서비스에서는 OpenSearch의 인스턴스를 만들게 됩니다. 이를 **노드**라고 합니다. 노드에서는 **인덱스**를 하나 이상 추가하게 됩니다. 인덱스는 개념적으로 관계형 데이터베이스의 테이블과 조금 비슷합니다. (하지만 OpenSearch는 ACID를 준수하지 않으므로 그와 같은 방식으로 사용해서는 안 됩니다.) OpenSearch 서비스에 업로드하는 데이터로 인덱스를 채우게 됩니다. 데이터가 업로드되면 인덱스 내에 있는 하나 이상의 샤드에 데이터를 인덱싱합니다. **샤드**는 일부 데이터를 포함하는 인덱스의 파티션과 같으며 다른 샤드와 별도로 쿼리할 수 있습니다. 업로드가 완료되면 데이터는 **문서**라는 JSON 파일로 구조화됩니다. 그러면 노드에 문서의 데이터를 쿼리할 수 있습니다.

### HTTP 엔드포인트
<a name="data-source-type-http"></a>

HTTP 엔드포인트를 데이터 소스로 사용할 수 있습니다. AWS AppSync는 파라미터 및 페이로드와 같은 관련 정보를 사용하여 엔드포인트에 요청을 보낼 수 있습니다. HTTP 응답은 해석기에 노출되며, 해석기는 작업이 완료된 후 최종 응답을 반환합니다.

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

데이터 소스를 생성한 경우 이를 AWS AppSync 서비스, 특히 API에 연결할 수 있습니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **대시보드**에서 API를 선택합니다.

   1. **사이드바**에서 **데이터 원본**을 선택합니다.

1. **데이터 원본 생성**을 선택합니다.

   1. 데이터 원본의 이름을 지정합니다. 원하는 경우 설명을 입력할 수도 있습니다.

   1. **데이터 원본 유형**을 선택합니다.

   1. DynamoDB의 경우 리전을 선택한 다음 리전의 테이블을 선택해야 합니다. 새로운 일반 테이블 역할을 만들거나 테이블의 기존 역할을 가져와서 테이블과의 상호 작용 규칙을 지정할 수 있습니다. [버전 관리](https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html)를 사용하도록 설정하여 여러 클라이언트가 동시에 데이터를 업데이트하려고 할 때 각 요청에 대한 데이터 버전을 자동으로 생성할 수 있습니다. 버전 관리는 충돌 감지 및 해결 목적으로 다양한 데이터 변형을 유지 및 관리하는 데 사용됩니다. 또한 데이터 원본을 가져오고 스키마에서 여기에 액세스하는 데 필요한 CRUD, `List`, `Query` 작업의 일부를 생성하는 자동 스키마 생성을 활성화할 수도 있습니다.

      OpenSearch의 경우 리전을 선택한 다음 리전의 도메인(클러스터) 을 선택해야 합니다. 새로운 일반 테이블 역할을 만들거나 테이블의 기존 역할을 가져와서 도메인과의 상호 작용 규칙을 지정할 수 있습니다.

      Lambda의 경우 리전을 선택한 다음 리전에서 Lambda 함수의 ARN을 선택해야 합니다. 새로운 일반 테이블 역할을 만들거나 테이블의 기존 역할을 가져와서 Lambda 함수와의 상호 작용 규칙을 지정할 수 있습니다.

      HTTP의 경우 HTTP 엔드포인트를 입력해야 합니다.

      EventBridge의 경우 리전을 선택한 다음 리전에서 이벤트 버스를 선택해야 합니다. 새로운 일반 테이블 역할을 만들거나 테이블의 기존 역할을 가져와서 이벤트 버스와의 상호 작용 규칙을 지정할 수 있습니다.

      RDS의 경우 리전을 선택한 다음 암호 저장소(사용자 이름 및 암호), 데이터베이스 이름, 스키마를 선택해야 합니다.

      없음의 경우 실제 데이터 원본이 없는 데이터 원본을 추가하게 됩니다. 이는 실제 데이터 원본을 통하지 않고 로컬에서 해석기를 처리하기 위함입니다.
**참고**  
기존 역할을 가져오는 경우 신뢰 정책이 필요합니다. 자세한 내용은 [IAM 신뢰 정책](#iam-trust-policy.title)을 참조하세요.

1. **생성(Create)**을 선택합니다.
**참고**  
또는 DynamoDB 데이터 원본을 생성하는 경우 콘솔의 **스키마** 페이지로 이동하여 페이지 상단에서 **리소스 생성**을 선택한 다음 사전 정의된 모델을 채워 테이블로 변환할 수 있습니다. 이 옵션에서는 기본 유형을 채우거나 가져오고, 파티션 키를 포함한 기본 테이블 데이터를 구성하고, 스키마 변경 사항을 검토합니다.

------
#### [ CLI ]
+ [https://docs.aws.amazon.com/cli/latest/reference/appsync/create-data-source.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-data-source.html) 명령을 실행하여 데이터 원본을 생성합니다.

  이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

  1. API의 `api-id`.

  1. 테이블의 `name`.

  1. 데이터 원본의 `type`. 선택한 데이터 원본 유형에 따라 `service-role-arn` 및 `-config` 태그를 입력해야 할 수 있습니다.

  예를 들어 명령은 다음과 같을 수 있습니다.

  ```
   aws appsync create-data-source --api-id abcdefghijklmnopqrstuvwxyz --name data_source_name --type data_source_type --service-role-arn arn:aws:iam::107289374856:role/role_name --[data_source_type]-config {params}
  ```

------
#### [ CDK ]

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/home.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
아래 나열된 단계는 특정 리소스를 추가하는 데 사용되는 스니펫의 일반적인 예시만 보여줍니다. 프로덕션 코드에서는 이 예시가 올바르게 작동하는 솔루션이 **아닙니다**. 또한 이미 작동하는 앱을 가지고 있는 것으로 가정합니다.

특정 데이터 원본을 추가하려면 스택 파일에 구성을 추가해야 합니다. 데이터 원본 유형 목록은 다음에서 찾을 수 있습니다.
+  [ DynamoDbDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
+  [ EventBridgeDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
+  [ HttpDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
+  [ LambdaDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
+  [ NoneDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
+  [ OpenSearchDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
+  [ RdsDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.RdsDataSource.html) 

1. 대개는 사용 중인 서비스에 가져오기 지침을 추가해야 할 수 있습니다. 예를 들면 다음 형식을 따를 수 있습니다.

   ```
   import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
   import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
   ```

   예를 들어, AWS AppSync 및 DynamoDB 서비스를 가져오는 방법은 다음과 같습니다.

   ```
   import * as appsync from 'aws-cdk-lib/aws-appsync';
   import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
   ```

1. RDS와 같은 일부 서비스는 데이터 원본을 생성하기 전에 스택 파일에 몇 가지 추가 설정이 필요합니다(예: VPC 생성, 역할, 액세스 보안 인증 정보). 자세한 내용은 관련 CDK 페이지의 예시를 참조하세요.

1. 대부분의 데이터 소스, 특히 AWS 서비스의 경우 스택 파일에 데이터 소스의 새 인스턴스를 생성합니다. 일반적으로 다음과 같습니다.

   ```
   const add_data_source_func = new service_scope.resource_name(scope: Construct, id: string, props: data_source_props);
   ```

   예를 들어 Amazon DynamoDB 테이블의 예는 다음과 같습니다.

   ```
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
     partitionKey: {
       name: 'id',
       type: dynamodb.AttributeType.STRING,
     },
     sortKey: {
       name: 'id',
       type: dynamodb.AttributeType.STRING,
     },
     tableClass: dynamodb.TableClass.STANDARD,
   });
   ```
**참고**  
대부분의 데이터 원본은 필수 속성을 하나 이상 갖습니다(`?` 기호 **없이** 표시됨). 어떤 속성이 필요한지 알아보려면 CDK 설명서를 참조하세요.

1. 다음으로 데이터 원본을 GraphQL API에 연결해야 합니다. 권장되는 방법은 파이프라인 해석기용 함수를 만들 때 추가하는 것입니다. 예를 들어 아래 스니펫은 DynamoDB 테이블의 모든 요소를 스캔하는 함수입니다.

   ```
   const add_func = new appsync.AppsyncFunction(this, 'func_ID', {
     name: 'func_name_in_console',
     add_api,
     dataSource: add_api.addDynamoDbDataSource('data_source_name_in_console', add_ddb_table),
     code: appsync.Code.fromInline(`
         export function request(ctx) {
           return { operation: 'Scan' };
         }
   
         export function response(ctx) {
           return ctx.result.items;
         }
     `),
     runtime: appsync.FunctionRuntime.JS_1_0_0,
   });
   ```

   `dataSource` 속성에서 GraphQL API(`add_api`)를 호출하고 기본 제공되는 메서드(`addDynamoDbDataSource`) 중 하나를 사용하여 테이블과 GraphQL API 사이의 연결을 설정할 수 있습니다. 인수는 AWS AppSync 콘솔에 존재할이 링크의 이름(`data_source_name_in_console`이 예제에서는 )과 테이블 메서드()입니다`add_ddb_table`. 이 주제에 대한 자세한 내용은 다음 섹션에서 해석기 제작을 시작하면서 설명하겠습니다.

   다른 방법으로도 데이터 원본을 연결할 수 있습니다. 기술적으로는 테이블 함수의 속성 목록에 `api`를 추가할 수 있습니다. 예를 들어 다음은 3단계의 스니펫이지만, 여기에는 GraphQL API가 포함된 `api` 속성이 있습니다.

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     ...
   });
   
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
   
    ...
   
     api: add_api
   });
   ```

   또는 `GraphqlApi` 구성을 별도로 호출할 수도 있습니다.

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     ...
   });
   
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
     ...
   });
   
   const link_data_source = add_api.addDynamoDbDataSource('data_source_name_in_console', add_ddb_table);
   ```

   함수의 속성에만 연결을 만드는 것이 좋습니다. 그렇지 않으면 AWS AppSync 콘솔에서 해석기 함수를 데이터 소스에 수동으로 연결하거나(콘솔 값을 계속 사용하려는 경우`data_source_name_in_console`) 함수에서와 같은 다른 이름으로 별도의 연결을 생성해야 합니다`data_source_name_in_console_2`. 이는 속성이 정보를 처리하는 방식에 제한이 있기 때문입니다.
**참고**  
변경 사항을 확인하려면 앱을 다시 배포해야 합니다.

------

### IAM 신뢰 정책
<a name="iam-trust-policy"></a>

데이터 소스에 기존 IAM 역할을 사용하는 경우 Amazon DynamoDB 테이블과 같은 AWS 리소스에서 작업을 수행할 수 `PutItem` 있는 적절한 권한을 해당 역할에 부여해야 합니다. 또한 다음 예제 정책과 같이 해당 역할의 신뢰 정책을 수정하여 AWS AppSync가 리소스 액세스에 사용할 수 있도록 해야 합니다.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
        "Effect": "Allow",
        "Principal": {
            "Service": "appsync.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
        }
    ]
}
```

------

신뢰 정책에 조건을 추가하여 데이터 원본에 대한 액세스를 원하는 대로 제한할 수도 있습니다. 현재 `SourceArn` 및 `SourceAccount` 키를 이러한 조건에 사용할 수 있습니다. 예를 들어 다음 정책에서는 데이터 원본에 대한 액세스를 `123456789012` 계정으로 제한합니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "123456789012"
        }
      }
    }
  ]
}
```

------

또는 다음 정책을 사용하여 데이터 원본에 대한 액세스를 특정 API(예: `abcdefghijklmnopq`)로 제한할 수 있습니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:appsync:us-west-2:123456789012:apis/abcdefghijklmnopq"
        }
      }
    }
  ]
}
```

------

다음 정책을 `us-east-1`사용하여와 같은 특정 리전의 모든 AWS AppSync APIs에 대한 액세스를 제한할 수 있습니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:appsync:us-east-1:123456789012:apis/*"
        }
      }
    }
  ]
}
```

------

다음 섹션([해석기 구성](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-config-overview.html))에서는 해석기 비즈니스 로직을 추가하고 이를 스키마의 필드에 연결하여 데이터 원본의 데이터를 처리합니다.

역할 정책 구성에 대한 자세한 내용은 *IAM 사용 설명서*의 [역할 변경](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_manage_modify.html)을 참조하세요.

 AWS AppSync용 AWS Lambda 해석기의 크로스 계정 액세스에 대한 자세한 내용은 [AWS AppSync용 크로스 계정 AWS Lambda 해석기 빌드](https://aws.amazon.com/blogs/mobile/appsync-lambda-cross-account/)를 참조하세요.

# AWS AppSync에서 해석기 구성
<a name="resolver-config-overview"></a>

이전 섹션에서는 GraphQL 스키마와 데이터 소스를 만든 다음 AWS AppSync 서비스에서 함께 연결하는 방법을 배웠습니다. 스키마에서 쿼리 및 뮤테이션에 하나 이상의 필드(작업)를 설정했을 수 있습니다. 스키마는 작업이 데이터 소스에서 요청하는 데이터 종류를 설명했지만, 해당 작업이 데이터에 대해 어떻게 동작하는지는 구현하지 못했습니다.

작업의 동작은 항상 해석기에서 구현되며, 해석기는 작업을 수행하는 필드에 연결됩니다. 해석기의 일반적인 작동 방식에 대한 자세한 내용은 [해석기](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html) 페이지를 참조하세요.

AWS AppSync에서 해석기는 해석기가 실행되는 환경인 런타임에 연결되어 있습니다. 런타임에 따라 해석기를 작성할 언어가 결정됩니다. 현재 지원되는 런타임은 APPSYNC\$1JS(JavaScript)와 Apache Velocity Template Language(VTL)입니다.

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

이 흐름은 파이프라인 해석기의 예입니다. 파이프라인 해석기는 두 런타임 모두에서 지원됩니다. 하지만 여기서는 파이프라인 해석기가 수행할 수 있는 작업에 대한 간단한 설명입니다. 또한 가능한 해석기 구성을 하나만 설명합니다. 지원되는 해석기 구성에 대한 자세한 내용은 APPSYNC\$1JS의 경우 [JavaScript 해석기 개요](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)를, 또는 VTL의 경우 [해석기 매핑 템플릿 개요](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-overview.html)를 참조하세요.

보시다시피 해석기는 모듈식입니다. 해석기의 구성 요소가 제대로 작동하려면 다른 구성 요소에서 실행 상태를 들여다볼 수 있어야 합니다. [해석기](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html) 섹션에서 해석기의 각 구성 요소는 인수 집합(`args`, `context` 등)으로 실행 상태에 대한 중요한 정보를 전달할 수 있다는 것을 확인했습니다. AWS AppSync에서는 이 작업을 `context`에서 엄격하게 처리합니다. 확인 중인 필드에 대한 정보를 담는 컨테이너입니다. 여기에는 전달되는 인수, 결과, 권한 부여 데이터, 헤더 데이터 등 모든 것이 포함될 수 있습니다. 컨텍스트에 대한 자세한 내용은 APPSYNC\$1JS의 경우 [해석기 컨텍스트 객체 참조](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)를, 또는 VTL의 경우 [해석기 매핑 템플릿 컨텍스트 참조](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html)를 참조하세요.

컨텍스트는 해석기를 구현하는 데 사용할 수 있는 유일한 도구가 아닙니다. AWS AppSync는 값 생성, 오류 처리, 구문 분석, 변환 등을 위한 광범위한 유틸리티를 지원합니다. APPSYNC\$1JS의 경우 [여기](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)에서 유틸리티 목록을 볼 수 있습니다.

다음 섹션에서는 GraphQL API에서 해석기를 구성하는 방법을 알아봅니다.

**Topics**
+ [기본 쿼리 생성(JavaScript)](configuring-resolvers-js.md)
+ [기본 쿼리 생성(VTL)](configuring-resolvers.md)

# 기본 쿼리 생성(JavaScript)
<a name="configuring-resolvers-js"></a>

GraphQL 해석기는 형식 스키마의 필드를 데이터 원본에 연결합니다. 해석기는 요청을 이행하는 메커니즘입니다.

 AWS AppSync의 해석기는 JavaScript를 사용하여 GraphQL 표현식을 데이터 소스가 사용할 수 있는 형식으로 변환합니다. 또는 [Apache Velocity Template Language(VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html)로 작성된 매핑 템플릿을 사용하여 GraphQL 식을 데이터 원본이 사용할 수 있는 형식으로 변환할 수 있습니다.

이 섹션에서는 JavaScript를 사용하여 해석기를 구성하는 방법을 설명합니다. [해석기 자습서(JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html) 섹션에서는 JavaScript를 사용하여 해석기를 구현하는 방법에 대한 심화된 자습서를 제공합니다. [해석기 참조(JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html) 섹션에서는 JavaScript 해석기와 함께 사용할 수 있는 유틸리티 작업에 대한 설명을 제공합니다.

앞서 언급한 자습서를 사용하기 전에 이 안내서를 확인하는 것이 좋습니다.

이 섹션에서는 쿼리와 변형을 위한 해석기를 만들고 구성하는 방법을 살펴보겠습니다.

**참고**  
이 안내서에서는 스키마를 만들었으며 쿼리 또는 변형이 하나 이상 있다고 가정합니다. 구독(실시간 데이터)을 찾고 있다면 [이](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html) 안내서를 참조하세요.

이 섹션에서는 아래 스키마를 사용하는 예제와 함께 해석기 구성을 위한 몇 가지 일반적인 단계를 제공합니다.

```
// schema.graphql file

input CreatePostInput {
  title: String
  date: AWSDateTime
}

type Post {
  id: ID!
  title: String
  date: AWSDateTime
}

type Mutation {
  createPost(input: CreatePostInput!): Post
}

type Query {
  getPost: [Post]
}
```

## 기본 쿼리 해석기 생성
<a name="create-basic-query-resolver-js"></a>

이 섹션에서는 기본 쿼리 해석기를 생성하는 방법을 보여 줍니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **스키마**를 선택합니다.

1. 스키마와 데이터 원본의 세부 정보를 입력합니다. 자세한 내용은 [스키마 설계](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html) 및 [데이터 원본 연결](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) 섹션을 참조하세요.

1. **스키마** 편집기 옆에는 **해석기**라는 창이 있습니다. 이 상자에는 **스키마** 창에 정의된 형식 및 필드 목록이 있습니다. 필드에 해석기를 연결할 수 있습니다. 주로 필드 작업에 해석기를 연결하게 될 것입니다. 이 섹션에서는 간단한 쿼리 구성을 살펴보겠습니다. **쿼리** 유형에서 쿼리 필드 옆에 있는 **연결**을 선택합니다.

1. **해석기 연결** 페이지의 **해석기 유형**에서 파이프라인 또는 단위 해석기 중에서 선택할 수 있습니다. 이러한 유형에 대한 자세한 내용은 [해석기](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)를 참조하세요. 이 안내서에서는 `pipeline resolvers`를 활용합니다.
**작은 정보**  
파이프라인 해석기를 생성하면 데이터 원본이 파이프라인 함수에 연결됩니다. 함수는 파이프라인 해석기를 생성한 후에 생성되므로 이 페이지에는 설정을 위한 옵션이 없습니다. 단위 해석기를 사용하는 경우 데이터 원본이 해석기에 직접 연결되므로 이 페이지에서 설정하게 됩니다.

   **해석기 런타임**의 경우 `APPSYNC_JS`를 선택하여 JavaScript 런타임을 활성화하세요.

1. 이 API에 [캐싱](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)을 활성화할 수 있습니다. 그러나 지금은 이 기능을 끄는 것이 좋습니다. **생성(Create)**을 선택합니다.

1. **해석기 편집** 페이지에는 해석기 핸들러 및 응답(사전 및 사후 단계)에 대한 로직을 구현할 수 있게 해주는 **해석기 코드**라는 코드 편집기가 있습니다. 자세한 내용은 [JavaScript 해석기 개요](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)를 참조하세요.
**참고**  
이 예에서는 요청을 비워 두고 [컨텍스트](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)의 마지막 데이터 원본 결과를 반환하도록 응답을 설정해 보겠습니다.  

   ```
   import {util} from '@aws-appsync/utils';
   
   export function request(ctx) {
       return {};
   }
   
   export function response(ctx) {
       return ctx.prev.result;
   }
   ```

   이 섹션 아래에는 **함수**라는 테이블이 있습니다. 함수를 사용하면 여러 해석기에서 재사용할 수 있는 코드를 구현할 수 있습니다. 코드를 계속 다시 작성하거나 복사하는 대신, 소스 코드를 함수로 저장하여 필요할 때마다 해석기에 추가되도록 할 수 있습니다.

   함수는 파이프라인 작업 목록의 대부분을 구성합니다. 해석기에서 여러 함수를 사용하는 경우 함수 순서를 설정하면 해당 순서대로 순차적으로 실행됩니다. 이러한 함수는 요청 함수가 실행된 후와 응답 함수가 시작되기 전에 실행됩니다.

   새 함수를 추가하려면 **함수**에서 **함수 추가**를 선택한 다음 **새 함수 생성**을 선택합니다. 또는 선택할 수 있는 **함수 생성** 버튼이 표시될 수도 있습니다.

   1. 데이터 원본을 선택합니다. 이 항목은 해석기가 작동하는 데이터 원본이 됩니다.
**참고**  
이 예제에서는 `id`로 `Post` 객체를 검색하는 `getPost`에 대한 해석기를 연결합니다. 이 스키마에 대한 DynamoDB 테이블을 이미 설정했다고 가정해 보겠습니다. 파티션 키는 `id`로 설정되어 있고 비어 있습니다.

   1. `Function name`을 입력합니다.

   1. **함수 코드**에서 함수의 동작을 구현해야 합니다. 헷갈릴 수도 있지만 각 함수에는 고유한 로컬 요청 및 응답 핸들러가 있습니다. 요청이 실행되면 요청을 처리하기 위한 데이터 원본 간접 호출이 수행되고, 응답 핸들러가 데이터 원본 응답을 처리합니다. 결과는 [컨텍스트](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html) 객체에 저장됩니다. 이후에는 목록의 다음 함수가 실행되거나 마지막 함수인 경우 사후 단계 응답 핸들러로 전달됩니다.
**참고**  
이 예제에서는 데이터 원본에서 `Post` 객체 목록을 가져오는 `getPost`에 해석기를 연결합니다. 요청 함수는 테이블에서 데이터를 요청하고, 테이블은 컨텍스트(ctx)에 응답을 전달한 다음, 응답은 컨텍스트에 결과를 반환합니다. AWS AppSync의 강도는 다른 AWS 서비스와의 상호 연결성에 있습니다. DynamoDB를 사용하고 있기 때문에 이와 같은 작업을 단순화할 수 있는 [일련의 작업](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html)이 있습니다. 다른 데이터 원본 유형에 대한 몇 가지 보일러플레이트 예제도 있습니다.  
코드는 다음과 같습니다.  

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * 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;
      }
      ```
이 단계에서는 두 가지 함수를 추가했습니다.  
`request`: 요청 핸들러는 데이터 원본에 대해 검색 작업을 수행합니다. 인수에는 컨텍스트 객체(`ctx`) 또는 특정 작업을 수행하는 모든 해석기에 사용할 수 있는 일부 데이터가 포함됩니다. 예를 들어 권한 부여 데이터, 해석 중인 필드 이름 등이 포함될 수 있습니다. 반환 문은 [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan) 작업을 수행합니다(예시는 [여기](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html)를 참조). DynamoDB로 작업 중이므로 해당 서비스의 일부 작업을 사용할 수 있습니다. 스캔은 테이블 내 모든 항목에 대한 기본 가져오기를 수행합니다. 이 작업의 결과는 응답 핸들러로 전달되기 전에 컨텍스트 객체에 `result` 컨테이너로 저장됩니다. `request`는 파이프라인에서 응답보다 먼저 실행됩니다.
`response`: `request`의 출력을 반환하는 응답 핸들러입니다. 인수는 업데이트된 컨텍스트 객체이고, 반환 문은 `ctx.prev.result`입니다. 이 시점에서는 이 값에 익숙하지 않을 수 있습니다. `ctx`는 컨텍스트 객체를 나타냅니다. `prev`는 파이프라인에서의 이전 작업을 나타내며, 여기에서는 `request`였습니다. `result`에는 파이프라인을 통과하는 해석기의 결과가 포함됩니다. 종합해 보면 `ctx.prev.result`는 마지막으로 수행된 작업, 즉 요청 핸들러의 결과를 반환합니다.

   1. 완료했으면 **생성**을 선택합니다.

1. 해석기 화면으로 돌아가서 **함수** 아래에서 **함수 추가** 드롭다운을 선택하고 함수를 함수 목록에 추가합니다.

1. **저장**을 선택하여 해석기를 업데이트합니다.

------
#### [ CLI ]

**함수를 추가하는 방법**
+ `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)` 명령을 사용하여 파이프라인 해석기용 함수를 생성합니다.

  이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

  1. API의 `api-id`.

  1.  AWS AppSync 콘솔에 있는 함수`name`의 입니다.

  1. `data-source-name` 또는 함수가 사용할 데이터 원본의 이름. 이미 생성되어 AWS AppSync 서비스에 있는 GraphQL API에 연결되어 있어야 합니다.

  1. `runtime` 또는 함수의 환경 및 언어. JavaScript의 경우 이름은 `APPSYNC_JS`, 런타임은 `1.0.0`이어야 합니다.

  1. `code` 또는 함수의 요청 및 응답 핸들러. 수동으로 입력할 수도 있지만 .txt 파일(또는 유사한 형식)에 추가한 다음 인수로 전달하는 것이 훨씬 쉽습니다.
**참고**  
쿼리 코드는 인수로 전달되는 파일에 있습니다.  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * 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;
     }
     ```

  예를 들어 명령은 다음과 같을 수 있습니다.

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name get_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file://~/path/to/file/{filename}.{fileType}
  ```

  CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

  ```
  {
      "functionConfiguration": {
          "functionId": "ejglgvmcabdn7lx75ref4qeig4",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/ejglgvmcabdn7lx75ref4qeig4",
          "name": "get_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```
**참고**  
함수를 해석기에 연결하는 데 사용되므로 `functionId`를 어딘가에 기록해 두어야 합니다.

**해석기 생성**
+ `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)` 명령을 실행하여 `Query`에 대한 파이프라인 함수를 생성합니다.

  이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

  1. API의 `api-id`.

  1. `type-name` 또는 스키마의 특수 객체 유형(쿼리, 변형, 구독).

  1. `field-name` 또는 해석기를 연결하려는 특수 객체 유형 내의 필드 작업.

  1. 단위 또는 파이프라인 해석기를 지정하는 `kind`. 파이프라인 함수를 활성화하려면 이 값을 `PIPELINE`으로 설정합니다.

  1. `pipeline-config` 또는 해석기에 연결할 함수. 함수의 `functionId` 값을 알고 있어야 합니다. 목록 순서가 중요합니다.

  1. `runtime`으로, 여기에서는 `APPSYNC_JS`(자바스크립트)였습니다. `runtimeVersion`은 현재 `1.0.0`입니다.

  1. `code`로, 사전 및 사후 단계 핸들러를 포함합니다.
**참고**  
쿼리 코드는 인수로 전달되는 파일에 있습니다.  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  예를 들어 명령은 다음과 같을 수 있습니다.

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Query \
  --field-name getPost \
  --kind PIPELINE \
  --pipeline-config functions=ejglgvmcabdn7lx75ref4qeig4 \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "getPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/getPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "ejglgvmcabdn7lx75ref4qeig4"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/home.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
아래 나열된 단계는 특정 리소스를 추가하는 데 사용되는 스니펫의 일반적인 예시만 보여줍니다. 프로덕션 코드에서는 이 예시가 올바르게 작동하는 솔루션이 **아닙니다**. 또한 이미 작동하는 앱을 가지고 있는 것으로 가정합니다.

기본 앱에는 다음 항목이 필요합니다.

1. 서비스 가져오기 지시문

1. 스키마 코드

1. 데이터 원본 생성기

1. 함수 코드

1. 해석기 코드

[스키마 설계](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html) 및 [데이터 원본 연결](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) 섹션을 통해 스택 파일에 다음과 같은 형식의 가져오기 지시문이 포함된다는 것을 알 수 있습니다.

```
import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
```

**참고**  
이전 단원에서는 AWS AppSync 구문을 가져오는 방법만 설명했습니다. 실제 코드에서는 앱을 실행하는 것만으로도 더 많은 서비스를 가져와야 합니다. 이 예제에서는 매우 간단한 CDK 앱을 생성하려는 경우 최소한 DynamoDB 테이블인 데이터 소스와 함께 AWS AppSync 서비스를 가져옵니다. 또한 앱을 배포하기 위해 몇 가지 추가 구성을 가져와야 했습니다.  

```
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
```
각 내용을 요약하면 다음과 같습니다.  
`import * as cdk from 'aws-cdk-lib';`: 이렇게 하면 CDK 앱 및 스택과 같은 구성을 정의할 수 있습니다. 여기에는 메타데이터 조작과 같은 애플리케이션에 유용한 유틸리티 함수도 포함되어 있습니다. 이 가져오기 지시문에 익숙하지만 여기에서 cdk 코어 라이브러리가 사용되지 않는 이유가 궁금하다면 [마이그레이션](https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html) 페이지를 참조하세요.
`import * as appsync from 'aws-cdk-lib/aws-appsync';`: [AWS AppSync 서비스](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 가져옵니다.
`import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';`: [DynamoDB 서비스](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb-readme.html)를 가져옵니다.
`import { Construct } from 'constructs';`: 루트 [구성](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html)을 정의하는 데 필요합니다.

가져오기 유형은 호출하는 서비스에 따라 달라집니다. 예를 보려면 CDK 설명서를 살펴보세요. 페이지 상단의 스키마는 CDK 앱의 파일로, `.graphql` 파일과는 별개입니다. 스택 파일에서 다음 형식을 사용하여 새 GraphQL과 연결할 수 있습니다.

```
const add_api = new appsync.GraphqlApi(this, 'graphQL-example', {
  name: 'my-first-api',
  schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema.graphql')),
});
```

**참고**  
범위 `add_api`에서는 `appsync.GraphqlApi(scope: Construct, id: string , props: GraphqlApiProps)` 뒤에 오는 `new` 키워드를 사용하여 새로운 GraphQL API를 추가합니다. 범위는 `this`, CFN id는 `graphQL-example`이며, 속성은 `my-first-api`(콘솔의 API 이름) 및 `schema.graphql`(스키마 파일의 절대 경로) 입니다.

데이터 원본을 추가하려면 먼저 데이터 원본을 스택에 추가해야 합니다. 그런 다음 소스별 메서드를 사용하여 GraphQL API와 연결해야 합니다. 해석기 함수를 만들면 연결이 이루어집니다. 그 동안 `dynamodb.Table`을 사용하여 DynamoDB 테이블을 생성하는 예제를 살펴보겠습니다.

```
const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
  partitionKey: {
    name: 'id',
    type: dynamodb.AttributeType.STRING,
  },
});
```

**참고**  
예제에서 이 방법을 사용한다면 CFN ID가 `posts-table`이고 파티션 키가 `id (S)`인 새로운 DynamoDB 테이블을 추가하게 됩니다.

다음으로 스택 파일에 해석기를 구현해야 합니다. 다음은 DynamoDB 테이블의 모든 항목을 스캔하는 간단한 쿼리의 예입니다.

```
const add_func = new appsync.AppsyncFunction(this, 'func-get-posts', {
  name: 'get_posts_func_1',
  add_api,
  dataSource: add_api.addDynamoDbDataSource('table-for-posts', add_ddb_table),
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return { operation: 'Scan' };
      }

      export function response(ctx) {
        return ctx.result.items;
      }
  `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
});

new appsync.Resolver(this, 'pipeline-resolver-get-posts', {
  add_api,
  typeName: 'Query',
  fieldName: 'getPost',
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return {};
      }

      export function response(ctx) {
        return ctx.prev.result;
      }
 `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
  pipelineConfig: [add_func],
});
```

**참고**  
먼저 `add_func`라는 함수를 만들었습니다. 이 생성 순서는 다소 직관적이지 않은 것처럼 보일 수 있지만, 해석기 자체를 만들기 전에 파이프라인 해석기에 함수를 만들어야 합니다. 함수는 다음과 같은 형식을 따릅니다.  

```
AppsyncFunction(scope: Construct, id: string, props: AppsyncFunctionProps)
```
범위는 `this`, CFN id는 `func-get-posts`였으며, 속성에는 실제 함수 세부 정보가 포함되어 있습니다. 속성 안에는 다음이 포함되었습니다.  
 AWS AppSync 콘솔에 있을 함수`name`의 입니다(`get_posts_func_1`).
앞서 만든 GraphQL API(`add_api`).
데이터 원본. 데이터 원본을 GraphQL API 값에 연결한 다음 함수에 연결하는 지점입니다. 생성한 테이블(`add_ddb_table`)을 가져와서 `GraphqlApi` 메서드([https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options)) 중 하나를 사용하여 GraphQL API(`add_api`)에 연결합니다. ID 값(`table-for-posts`)은 AWS AppSync 콘솔에 있는 데이터 원본의 이름입니다. 소스별 메서드 목록은 다음 페이지를 참조하세요.  
[ DynamoDbDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
 [ EventBridgeDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
 [ HttpDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
 [ LambdaDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
 [ NoneDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
 [ OpenSearchDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
 [ RdsDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.RdsDataSource.html) 
코드에는 간단한 스캔 및 반환인 함수의 요청 및 응답 핸들러가 포함되어 있습니다.
런타임은 APPSYNC\$1JS 런타임 버전 1.0.0을 사용하도록 지정합니다. 참고로 이 버전은 현재 APPSYNC\$1JS에서 사용할 수 있는 유일한 버전입니다.
다음으로 함수를 파이프라인 해석기에 연결해야 합니다. 다음과 같은 형식을 사용하여 해석기를 생성했습니다.  

```
Resolver(scope: Construct, id: string, props: ResolverProps)
```
범위는 `this`, CFN id는 `pipeline-resolver-get-posts`였으며, 속성에는 실제 함수 세부 정보가 포함되어 있습니다. 속성 안에는 다음이 포함되었습니다.  
앞서 만든 GraphQL API(`add_api`).
특수 객체 유형 이름. 쿼리 작업이므로 `Query` 값을 추가하기만 하면 됩니다.
필드 이름(`getPost`)은 `Query` 유형 아래의 스키마에 있는 필드 이름입니다.
코드에는 사전 및 사후 핸들러가 포함되어 있습니다. 이 예제는 함수가 작업을 수행한 후 컨텍스트에 있었던 모든 결과를 반환합니다.
런타임은 APPSYNC\$1JS 런타임 버전 1.0.0을 사용하도록 지정합니다. 참고로 이 버전은 현재 APPSYNC\$1JS에서 사용할 수 있는 유일한 버전입니다.
파이프라인 구성에는 생성한 함수(`add_func`)에 대한 참조가 포함되어 있습니다.

------

이 예제에서 발생한 일을 요약하기 위해 요청 및 응답 핸들러를 구현한 AWS AppSync 함수를 보았습니다. 함수는 데이터 원본과의 상호 작용을 담당했습니다. 요청 핸들러가 DynamoDB 데이터 소스에 대해 수행할 `Scan` 작업에 대해 AWS AppSync지시하는 작업을에 보냈습니다. 응답 핸들러는 항목의 목록(`ctx.result.items`)을 반환했습니다. 그런 다음 항목 목록이 `Post` GraphQL 유형에 자동으로 매핑되었습니다.

## 기본 변형 해석기 생성
<a name="creating-basic-mutation-resolvers-js"></a>

이 섹션에서는 기본 변형 해석기를 생성하는 방법을 보여 줍니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **스키마**를 선택합니다.

1. **해석기** 섹션 및 **변형** 유형에서 필드 옆에 있는 **연결**을 선택합니다.
**참고**  
이 예제에서는 테이블에 `Post` 객체를 추가하는 `createPost`에 대한 해석기를 연결합니다. 마지막 섹션과 동일한 DynamoDB 테이블을 사용한다고 가정해 보겠습니다. 파티션 키는 `id`로 설정되어 있고 비어 있습니다.

1. **해석기 연결** 페이지의 **해석기 유형**에서 `pipeline resolvers`를 선택합니다. 참고로 해석기에 대한 추가 정보는 [여기](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)에서 확인할 수 있습니다. **해석기 런타임**의 경우 `APPSYNC_JS`를 선택하여 JavaScript 런타임을 활성화하세요.

1. 이 API에 [캐싱](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)을 활성화할 수 있습니다. 그러나 지금은 이 기능을 끄는 것이 좋습니다. **생성(Create)**을 선택합니다.

1. **함수 추가**를 선택한 다음 **새 함수 생성**을 선택합니다. 또는 선택할 수 있는 **함수 생성** 버튼이 표시될 수도 있습니다.

   1. 데이터 원본을 선택합니다. 변형을 사용하여 조작할 데이터가 들어 있는 원본이어야 합니다.

   1. `Function name`을 입력합니다.

   1. **함수 코드**에서 함수의 동작을 구현해야 합니다. 이는 변형이므로 요청은 간접적으로 호출된 데이터 원본에서 일부 상태 변경 작업을 수행하는 것이 이상적입니다. 결과는 응답 함수에 의해 처리됩니다.
**참고**  
`createPost`는 파라미터를 데이터로 사용하여 테이블에 새 `Post`를 추가하거나 '퍼팅'합니다. 다음과 같이 추가할 수 있습니다.  

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * Sends a request to `put` an item in the DynamoDB data source
       */
      export function request(ctx) {
        return {
          operation: 'PutItem',
          key: util.dynamodb.toMapValues({id: util.autoId()}),
          attributeValues: util.dynamodb.toMapValues(ctx.args.input),
        };
      }
      
      /**
       * returns the result of the `put` operation
       */
      export function response(ctx) {
        return ctx.result;
      }
      ```
이 단계에서 `request` 및 `response` 함수도 추가했습니다.  
`request`: 요청 핸들러는 컨텍스트를 인수로 받아들입니다. 요청 핸들러 반환 문은 내장된 DynamoDB 작업인 [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem) 명령을 수행합니다(예시는 [여기](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-2.html) 또는 [여기](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.WritingData) 참조). `PutItem` 명령은 파티션 `key` 값(`util.autoid()`에서 자동으로 생성됨)과 컨텍스트 인수 입력의 `attributes`(요청 시 전달할 값)를 가져와 DynamoDB 테이블에 `Post` 객체를 추가합니다. `key`는 `id`이고 `attributes`는 `date` 및 `title` 필드 인수입니다. 둘 다 DynamoDB 테이블에서 작동하도록 [https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js](https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js) 도우미를 통해 미리 형식이 지정되어 있습니다.
`response`: 응답은 업데이트된 컨텍스트를 수락하고 요청 핸들러의 결과를 반환합니다.

   1. 완료했으면 **생성**을 선택합니다.

1. 해석기 화면으로 돌아가서 **함수** 아래에서 **함수 추가** 드롭다운을 선택하고 함수를 함수 목록에 추가합니다.

1. **저장**을 선택하여 해석기를 업데이트합니다.

------
#### [ CLI ]

**함수를 추가하는 방법**
+ `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)` 명령을 사용하여 파이프라인 해석기용 함수를 생성합니다.

  이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

  1. API의 `api-id`.

  1.  AWS AppSync 콘솔에 있는 함수`name`의 입니다.

  1. `data-source-name` 또는 함수가 사용할 데이터 원본의 이름. 이미 생성되어 AWS AppSync 서비스에 있는 GraphQL API에 연결되어 있어야 합니다.

  1. `runtime` 또는 함수의 환경 및 언어. JavaScript의 경우 이름은 `APPSYNC_JS`, 런타임은 `1.0.0`이어야 합니다.

  1. `code` 또는 함수의 요청 및 응답 핸들러. 수동으로 입력할 수도 있지만 .txt 파일(또는 유사한 형식)에 추가한 다음 인수로 전달하는 것이 훨씬 쉽습니다.
**참고**  
쿼리 코드는 인수로 전달되는 파일에 있습니다.  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({id: util.autoId()}),
         attributeValues: util.dynamodb.toMapValues(ctx.args.input),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  예를 들어 명령은 다음과 같을 수 있습니다.

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name add_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

  ```
  {
      "functionConfiguration": {
          "functionId": "vulcmbfcxffiram63psb4dduoa",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/vulcmbfcxffiram63psb4dduoa",
          "name": "add_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output foes here"
      }
  }
  ```
**참고**  
함수를 해석기에 연결하는 데 사용되므로 `functionId`를 어딘가에 기록해 두어야 합니다.

**해석기 생성**
+ `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)` 명령을 실행하여 `Mutation`에 대한 파이프라인 함수를 생성합니다.

  이 특정 명령에 대해 몇 가지 파라미터를 입력해야 합니다.

  1. API의 `api-id`.

  1. `type-name` 또는 스키마의 특수 객체 유형(쿼리, 변형, 구독).

  1. `field-name` 또는 해석기를 연결하려는 특수 객체 유형 내의 필드 작업.

  1. 단위 또는 파이프라인 해석기를 지정하는 `kind`. 파이프라인 함수를 활성화하려면 이 값을 `PIPELINE`으로 설정합니다.

  1. `pipeline-config` 또는 해석기에 연결할 함수. 함수의 `functionId` 값을 알고 있어야 합니다. 목록 순서가 중요합니다.

  1. `runtime`으로, 여기에서는 `APPSYNC_JS`(자바스크립트)였습니다. `runtimeVersion`은 현재 `1.0.0`입니다.

  1. `code`로, 사전 및 사후 단계를 포함합니다.
**참고**  
쿼리 코드는 인수로 전달되는 파일에 있습니다.  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  예를 들어 명령은 다음과 같을 수 있습니다.

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Mutation \
  --field-name createPost \
  --kind PIPELINE \
  --pipeline-config functions=vulcmbfcxffiram63psb4dduoa \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "createPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/createPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "vulcmbfcxffiram63psb4dduoa"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/home.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
아래 나열된 단계는 특정 리소스를 추가하는 데 사용되는 스니펫의 일반적인 예시만 보여줍니다. 프로덕션 코드에서는 이 예시가 올바르게 작동하는 솔루션이 **아닙니다**. 또한 이미 작동하는 앱을 가지고 있는 것으로 가정합니다.
+ 변형을 만들려면 같은 프로젝트에 참여하고 있다고 가정하고 쿼리처럼 스택 파일에 추가하면 됩니다. 테이블에 새 `Post`를 추가하는 변형에 대한 수정된 함수와 해석기는 다음과 같습니다.

  ```
  const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', {
    name: 'add_posts_func_1',
    add_api,
    dataSource: add_api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table),
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {
                operation: 'PutItem',
                key: util.dynamodb.toMapValues({id: util.autoId()}),
                attributeValues: util.dynamodb.toMapValues(ctx.args.input),
              };
            }
  
            export function response(ctx) {
              return ctx.result;
            }
        `), 
    runtime: appsync.FunctionRuntime.JS_1_0_0,
  });
  
  new appsync.Resolver(this, 'pipeline-resolver-create-posts', {
    add_api,
    typeName: 'Mutation',
    fieldName: 'createPost',
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {};
            }
  
            export function response(ctx) {
              return ctx.prev.result;
            }
        `),
    runtime: appsync.FunctionRuntime.JS_1_0_0,
    pipelineConfig: [add_func_2],
  });
  ```
**참고**  
이 변형과 쿼리는 구조가 비슷하므로 변형을 만들기 위해 변경한 내용만 설명하겠습니다.  
테이블에 `Posts`를 추가한다는 사실을 반영하기 위해 함수에서 CFN id를 `func-add-post`로 변경하고 이름을 `add_posts_func_1`로 변경했습니다. 데이터 소스에서는 `addDynamoDbDataSource` 메서드에 필요하기 `table-for-posts-2` 때문에 AWS AppSync 콘솔의 테이블(`add_ddb_table`)에 로 새 연결을 만들었습니다. 이 새 연결은 이전에 생성한 것과 동일한 테이블을 계속 사용하고 있지만 이제 AWS AppSync 콘솔에 두 개의 연결이 있습니다. 하나는 쿼리용`table-for-posts`이고 다른 하나는 변형용입니다`table-for-posts-2`. `id` 값을 자동으로 생성하고 나머지 필드에 대해 클라이언트의 입력을 수락하여 `Post`를 추가하도록 코드가 변경되었습니다.  
테이블에 `Posts`를 추가한다는 사실을 반영하기 위해 해석기에서 id 값을 `pipeline-resolver-create-posts`로 변경했습니다. 스키마에 변형를 반영하기 위해 유형 이름은 `Mutation`으로, 이름은 `createPost`로 변경되었습니다. 파이프라인 구성이 새 변형 함수 `add_func_2`로 설정되었습니다.

------

이 예제에서 일어나는 일을 요약하기 위해는 `createPost` 필드에 정의된 인수를 GraphQL 스키마에서 DynamoDB 작업으로 AWS AppSync 자동 변환합니다. 이 예제에서는 `util.autoId()` 도우미를 사용하여 자동으로 생성되는 `id`의 키를 사용하여 DynamoDB에 레코드를 저장합니다. AWS AppSync 콘솔 또는 기타에서 수행된 요청의 컨텍스트 인수(`ctx.args.input`)에 전달하는 다른 모든 필드는 테이블의 속성으로 저장됩니다. 키와 특성 모두 `util.dynamodb.toMapValues(values)` 도우미를 사용하여 호환되는 DynamoDB 형식에 자동으로 매핑됩니다.

AWS AppSync 는 해석기 편집을 위한 테스트 및 디버그 워크플로도 지원합니다. 모의 `context` 객체를 사용하여 간접 호출 전에 템플릿의 변환된 값을 확인할 수 있습니다. 선택적으로 쿼리를 실행할 때 대화식으로 데이터 원본에 대한 전체 요청을 볼 수 있습니다. 자세한 내용은 [해석기 테스트 및 디버깅(JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/test-debug-resolvers-js.html) 및 [모니터링 및 로깅](https://docs.aws.amazon.com/appsync/latest/devguide/monitoring.html#aws-appsync-monitoring)을 참조하세요.

## 고급 해석기
<a name="advanced-resolvers-js"></a>

[스키마 설계](designing-your-schema.md#aws-appsync-designing-your-schema)의 선택적 페이지 매김 섹션을 따르는 경우에도 페이지 매김을 사용하려면 요청에 해석기를 추가해야 합니다. 이 예제에서는 한 번에 요청된 항목 중 일부만 반환하도록 `getPosts`라는 쿼리 페이지 매김을 사용했습니다. 해당 필드의 해석기 코드는 다음과 같을 수 있습니다.

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  const { limit = 20, nextToken } = ctx.args;
  return { operation: 'Scan', limit, nextToken };
}

/**
 * @returns the result of the `put` operation
 */
export function response(ctx) {
  const { items: posts = [], nextToken } = ctx.result;
  return { posts, nextToken };
}
```

요청에서는 요청의 컨텍스트를 전달합니다. `limit`은 *20*으로, 첫 번째 쿼리에서 최대 20개의 `Posts`를 반환합니다. `nextToken` 커서는 데이터 원본의 첫 번째 `Post` 항목에 고정됩니다. 이러한 값은 인수로 전달됩니다. 그런 다음 요청은 첫 번째 `Post`부터 시작하여 스캔 제한 횟수까지 스캔을 수행합니다. 데이터 원본은 결과를 컨텍스트에 저장하고, 이 결과는 응답에 전달됩니다. 응답은 검색된 `Posts`를 반환한 다음 `nextToken`을 한도 바로 뒤의 `Post` 항목으로 설정합니다. 정확히 동일한 작업을 수행하지만 첫 번째 쿼리 직후의 오프셋부터 시작하도록 다음 요청이 전송됩니다. 이러한 종류의 요청은 병렬로 수행되지 않고 순차적으로 수행된다는 점에 유의하세요.

# AWS AppSync에서 해석기 테스트 및 디버깅(JavaScript)
<a name="test-debug-resolvers-js"></a>

AWS AppSync는 데이터 소스에 대해 GraphQL 필드에서 해석기를 실행합니다. 파이프라인 해석기로 작업할 때 함수는 데이터 소스와 상호 작용합니다. [JavaScript 해석기 개요](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html) 설명된 대로 함수는 JavaScript로 작성되고 `APPSYNC_JS` 런타임에서 실행되는 요청 및 응답 핸들러를 사용하여 데이터 소스와 통신합니다. 이를 통해 데이터 소스와 통신하기 전과 후에 사용자 지정 로직 및 조건을 제공할 수 있습니다.

개발자가 이러한 해석기를 작성, 테스트 및 디버깅할 수 있도록 AWS AppSync 콘솔은 모의 데이터가 포함된 GraphQL 요청 및 응답을 개별 필드 해석기로 생성하는 도구도 제공합니다. 또한 AWS AppSync 콘솔에서 쿼리, 변형 및 구독을 수행하고 Amazon CloudWatch의 전체 요청에 대한 자세한 로그 스트림을 볼 수 있습니다. 여기에는 데이터 소스의 결과가 포함됩니다.

## 모의 데이터를 사용하여 테스트
<a name="testing-with-mock-data-js"></a>

GraphQL 해석기가 호출되는 경우 이 해석기에는 요청에 대한 관련 정보를 포함하는 `context` 객체가 들어 있습니다. 여기에는 클라이언트의 인수, 자격 증명 정보 및 상위 GraphQL 필드의 데이터가 포함됩니다. 또한 데이터 소스의 결과를 저장하며, 이러한 결과는 응답 핸들러에서 사용할 수 있습니다. 이 구조와 프로그래밍 시 사용할 수 있는 도우미 유틸리티에 대한 자세한 내용은 [해석기 컨텍스트 객체 참조](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html) 단원을 참조하세요.

해석기 함수를 작성하거나 편집할 때 *mock* 또는 *test context* 객체를 콘솔 편집기로 전달할 수 있습니다. 이렇게 하면 데이터 원본에 대해 실행하지 않고도 요청과 응답 핸들러가 어떻게 평가되는지 알아볼 수 있습니다. 예를 들면 테스트 `firstname: Shaggy` 인수를 전달하고 템플릿 코드에서 `ctx.args.firstname`을 사용하면 이 인수가 어떻게 평가되는지 볼 수 있습니다. 또한 `util.autoId()` 또는 `util.time.nowISO8601()` 같은 유틸리티 도우미의 평가도 테스트할 수 있습니다.

### 해석기 테스트
<a name="test-a-resolver-js"></a>

이 예제에서는 AWS AppSync 콘솔을 사용하여 해석기를 테스트합니다.

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **함수**를 선택합니다.

1. 기존 함수를 선택합니다.

1. **함수 업데이트** 페이지 상단에서 **테스트 컨텍스트 선택**을 선택한 다음 **새 컨텍스트 생성**을 선택합니다.

1. 샘플 컨텍스트 객체를 선택하거나 아래 **테스트 컨텍스트 구성** 창에서 JSON을 수동으로 채웁니다.

1. **텍스트 컨텍스트 이름**을 입력합니다.

1. **저장** 버튼을 선택합니다.

1. 이 모의 컨텍스트 객체를 사용하여 해석기를 평가하려면 **테스트 실행**을 선택합니다.

보다 실용적인 예로, 객체에 대한 자동 ID 생성을 사용하고 이를 Amazon DynamoDB에 저장하는 `Dog`의 GraphQL 유형을 저장하는 앱이 있다고 가정해 보겠습니다. 또한 GraphQL 뮤테이션의 인수에서 일부 값을 작성하고 특정 사용자만 응답을 볼 수 있도록 허용하려고 합니다. 다음 코드 조각은 스키마의 모양을 보여줍니다.

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

 AWS AppSync 함수를 작성하여 `addDog` 해석기에 추가하여 변형을 처리할 수 있습니다. AWS AppSync 함수를 테스트하려면 다음 예제와 같이 컨텍스트 객체를 채울 수 있습니다. 다음 객체에는 `name` 및 `age` 클라이언트의 인수와 `identity` 객체에 채워진 `username`이 있습니다.

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

다음 코드를 사용하여 AWS AppSync 함수를 테스트할 수 있습니다.

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
  return {
    operation: 'PutItem',
    key: util.dynamodb.toMapValues({ id: util.autoId() }),
    attributeValues: util.dynamodb.toMapValues(ctx.args),
  };
}

export function response(ctx) {
  if (ctx.identity.username === 'Nadia') {
    console.log("This request is allowed")
    return ctx.result;
  }
  util.unauthorized();
}
```

평가된 요청 및 응답 핸들러에는 테스트 컨텍스트 객체의 데이터와 `util.autoId()`에서 생성된 값이 포함됩니다. 또한, `username`을 `Nadia` 이외의 값으로 변경해야 했다면 권한 부여 확인이 실패하므로 결과가 반환되지 않습니다. 세분화된 액세스 제어에 대한 자세한 내용은 [권한 부여 사용 사례](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases) 단원을 참조하세요.

### AWS AppSync의 APIs를 사용하여 요청 및 응답 핸들러 테스트
<a name="testing-with-appsync-api-js"></a>

`EvaluateCode` API 명령어를 사용하여 모의 데이터로 코드를 원격 테스트할 수 있습니다. 명령어를 시작하려면 정책에 `appsync:evaluateMappingCode` 권한을 추가했는지 확인하세요. 예제:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:evaluateCode",
            "Resource": "arn:aws:appsync:us-east-1:111122223333:*"
        }
    ]
}
```

------

[AWS CLI](https://aws.amazon.com/cli/) 또는 [AWS SDK](https://aws.amazon.com/tools/)를 사용하여 명령을 활용할 수 있습니다. 예를 들어 이전 섹션의 `Dog` 스키마와 해당 AWS AppSync 함수 요청 및 응답 핸들러를 살펴보겠습니다. 로컬 스테이션에서 CLI를 사용하여 코드를 `code.js`라는 파일에 저장한 다음 `context` 객체를 `context.json`이라는 파일에 저장합니다. 쉘에서 다음 명령을 실행합니다.

```
$ aws appsync evaluate-code \
  --code file://code.js \
  --function response \
  --context file://context.json \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0
```

응답에는 핸들러가 반환한 페이로드가 포함된 `evaluationResult`가 포함되어 있습니다. 또한 평가 중에 핸들러가 생성한 로그 목록이 들어 있는 `logs` 객체도 포함되어 있습니다. 이렇게 하면 코드 실행을 쉽게 디버깅하고 평가에 대한 정보를 확인하여 문제를 해결하는 데 도움이 됩니다. 예제:

```
{
    "evaluationResult": "{\"breed\":\"Miniature Schnauzer\",\"color\":\"black_grey\"}",
    "logs": [
        "INFO - code.js:13:5: \"This request is allowed\""
    ]
}
```

`evaluationResult`를 JSON으로 구문 분석하여 다음과 같은 결과를 얻을 수 있습니다.

```
{
  "breed": "Miniature Schnauzer",
  "color": "black_grey"
}
```

SDK를 사용하면 자주 사용하는 테스트 제품군의 테스트를 쉽게 통합하여 핸들러의 동작을 검증할 수 있습니다. [Jest 테스트 프레임워크](https://jestjs.io/)를 사용하여 테스트를 생성하는 것을 권장하지만, 어떤 테스트 도구도 사용 가능합니다. 다음 코드 조각은 가상의 검증 실행을 보여줍니다. 평가 응답은 유효한 JSON일 것으로 예상하므로 `JSON.parse`를 사용하여 문자열 응답에서 JSON을 검색합니다.

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })
const runtime = {name:'APPSYNC_JS',runtimeVersion:'1.0.0')

test('request correctly calls DynamoDB', async () => {
  const code = fs.readFileSync('./code.js', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateCode({ code, context, runtime, function: 'request' }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 이 결과는 다음과 같아야 합니다.

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 totalTime: 1.511 s, estimated 2 s
```

## 라이브 쿼리 디버깅
<a name="debugging-a-live-query-js"></a>

프로덕션 애플리케이션을 디버깅하기 위한 end-to-end 테스트 및 로깅을 대체할 수 없습니다. AWS AppSync를 사용하면 Amazon CloudWatch를 사용하여 오류와 전체 요청 세부 정보를 로깅할 수 있습니다. 또한 AWS AppSync 콘솔을 사용하여 각 요청에 대한 GraphQL 쿼리, 변형 및 구독과 라이브 스트림 로그 데이터를 테스트하고 쿼리 편집기로 다시 전송하여 실시간으로 디버깅할 수 있습니다. 구독의 경우 로그는 연결-시간 정보를 표시합니다.

이를 수행하려면 [모니터링 및 로깅](monitoring.md#aws-appsync-monitoring)에 설명된 대로 Amazon CloudWatch 로그를 미리 활성화해야 합니다. 그런 다음 AWS AppSync 콘솔에서 **쿼리** 탭을 선택한 다음 유효한 GraphQL 쿼리를 입력합니다. 오른쪽 하단 섹션에서 **로그** 창을 클릭하고 드래그하여 로그 보기를 엽니다. 페이지 맨 위에 있는 ‘재생’ 화살표 아이콘을 선택하여 GraphQL 쿼리를 실행합니다. 몇 분 후 작업에 대한 전체 요청 및 응답 로그가 이 섹션으로 스트리밍되어 사용자가 콘솔에서 볼 수 있습니다.

# AWS AppSync(JavaScript)에서 파이프라인 해석기 구성 및 사용
<a name="pipeline-resolvers-js"></a>

AWS AppSync는 GraphQL 필드에서 해석기를 실행합니다. 경우에 따라 애플리케이션 사용 시 단일 GraphQL 필드를 해석하기 위해 여러 작업을 실행해야 합니다. 이제, 파이프라인 해석기를 사용해 개발자는 함수라고 하는 작업을 작성하고 순서대로 실행할 수 있습니다. 파이프라인 해석기는 예를 들어, 필드에 필요한 데이터를 가져오기 전에 권한 부여를 확인해야 하는 애플리케이션에 유용합니다.

JavaScript 파이프라인 해석기의 아키텍처에 대한 자세한 내용은 [JavaScript 해석기 개요](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html#anatomy-of-a-pipeline-resolver-js)를 참조하세요.

## 1단계: 파이프라인 해석기 생성
<a name="create-a-pipeline-resolver-js"></a>

 AWS AppSync 콘솔에서 **스키마** 페이지로 이동합니다.

다음 스키마를 저장합니다.

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

type Mutation {
    signUp(input: Signup): User
}

type Query {
    getUser(id: ID!): User
}

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

**변형** 유형의 **signUp** 필드에 파이프라인 해석기를 연결하겠습니다. 오른쪽에 있는 **변형** 유형에서 `signUp` 변형 필드 옆에 있는 **연결**을 선택합니다. 해석기를 `pipeline resolver`로 설정하고 `APPSYNC_JS` 런타임을 설정한 다음 해석기를 생성합니다.

파이프라인 해석기는 사용자를 등록해 먼저 입력된 이메일 주소를 확인한 다음 사용자를 시스템에 저장합니다. 이메일 검증을 **validateEmail** 함수 내에 캡슐화하고 사용자를 **saveUser** 함수 내에 저장할 것입니다. **validateEmail** 함수가 먼저 실행되고, 이메일이 유효한 경우 **saveUser** 함수가 실행됩니다.

다음과 같이 실행 흐름이 진행됩니다.

1. Mutation.signUp 해석기 요청 핸들러

1. validateEmail 함수

1. saveUser 함수

1. Mutation.signUp 해석기 응답 핸들러

API의 다른 해석기 내에서 **validateEmail** 함수를 다시 사용할 것입니다. GraphQL 필드 간에 변경되기 때문에 `ctx.args`에는 액세스하지 않도록 하겠습니다. 대신 `ctx.stash`를 사용해 `signUp(input: Signup)` 입력 필드 인수의 이메일 속성을 저장할 수 있습니다.

요청 및 응답 함수를 바꿔서 해석기 코드를 업데이트하세요.

```
export function request(ctx) {
    ctx.stash.email = ctx.args.input.email
    return {};
}

export function response(ctx) {
    return ctx.prev.result;
}
```

**생성** 또는 **저장**을 선택하여 해석기를 업데이트합니다.

## 2단계: 함수 생성
<a name="create-a-function-js"></a>

파이프라인 해석기 페이지의 **함수** 섹션에서 **함수 추가**를 클릭하고 **새 함수 생성**을 클릭합니다. 해석기 페이지를 거치지 않고 함수를 생성할 수도 있습니다. 이렇게 하려면 AWS AppSync 콘솔에서 **함수** 페이지로 이동합니다. **함수 생성** 버튼을 선택합니다. 이메일이 유효하고 특정 도메인에서 전송되는지 확인하는 함수를 생성합니다. 이메일이 유효하지 않으면 함수에서 오류가 발생합니다. 이메일이 유효할 경우 제공된 입력을 전달합니다.

**없음** 유형의 데이터 원본을 생성했는지 확인합니다. **데이터 원본 이름** 목록에서 이 데이터 원본을 선택합니다. **함수 이름**에 `validateEmail`을 입력합니다. **함수 코드** 영역에서 다음 스니펫으로 모든 내용을 덮어씁니다.

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
  const { email } = ctx.stash;
  const valid = util.matches(
    '^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com',
    email
  );
  if (!valid) {
    util.error(`"${email}" is not a valid email.`);
  }

  return { payload: { email } };
}

export function response(ctx) {
  return ctx.result;
}
```

입력 내용을 검토한 다음 **생성**을 선택합니다. 방금 **validateEmail** 함수를 생성했습니다. 이 단계를 반복하여 다음 코드로 **saveUser** 함수를 생성합니다(단순화를 위해 **없음** 데이터 원본을 사용하고 함수가 실행된 후 사용자가 시스템에 저장된 것으로 가장함).

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
  return ctx.prev.result;
}

export function response(ctx) {
  ctx.result.id = util.autoId();
  return ctx.result;
}
```

방금 **saveUser** 함수를 생성했습니다.

## 3단계: 파이프라인 해석기에 함수 추가
<a name="adding-a-function-to-a-pipeline-resolver-js"></a>

파이프라인 해석기에 방금 생성한 함수가 자동으로 추가되어야 합니다. 그렇지 않거나 **함수** 페이지를 통해 함수를 생성한 경우, `signUp` 해석기 페이지에서 **함수 추가**를 다시 클릭하여 연결할 수 있습니다. 해석기에 **validateEmail** 및 **saveUser** 함수를 모두 추가합니다. **validateEmail** 함수는 **saveUser** 함수 앞에 배치해야 합니다. 함수를 더 추가할 때 **위로 이동** 및 **아래로 이동** 옵션을 사용해 함수 실행 순서를 다시 정리할 수 있습니다. 변경 사항을 검토한 후 **저장**을 선택합니다.

## 4단계: 쿼리 실행
<a name="running-a-query-js"></a>

 AWS AppSync 콘솔에서 **쿼리** 페이지로 이동합니다. 탐색기에서 변형을 사용하고 있는지 확인합니다. 그렇지 않다면 드롭다운 목록에서 `Mutation`을 선택한 다음 `+`를 선택합니다. 다음 쿼리를 입력합니다.

```
mutation {
  signUp(input: {email: "nadia@myvaliddomain.com", username: "nadia"}) {
    id
    username
  }
}
```

다음과 유사하게 반환되어야 합니다.

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "username": "nadia"
    }
  }
}
```

파이프라인 해석기를 사용하여 성공적으로 사용자를 등록했고, 입력한 이메일을 검증했습니다.

# 기본 쿼리 생성(VTL)
<a name="configuring-resolvers"></a>

**참고**  
이제 우리는 주로 APPSYNC\$1JS 런타임과 해당 문서를 지원합니다. [여기](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)에서 APPSYNC\$1JS 런타임과 해당 안내서를 사용해 보세요.

GraphQL 해석기는 형식 스키마의 필드를 데이터 원본에 연결합니다. 해석기는 요청이 이행되는 메커니즘입니다. AWS AppSync는 코드를 작성할 필요 없이 스키마에서 해석기를 자동으로 생성 및 연결하거나 기존 테이블에서 스키마를 생성하고 해석기를 연결할 수 있습니다.

 AWS AppSync의 해석기는 JavaScript를 사용하여 GraphQL 표현식을 데이터 소스가 사용할 수 있는 형식으로 변환합니다. 또는 [Apache Velocity Template Language(VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html)로 작성된 매핑 템플릿을 사용하여 GraphQL 식을 데이터 원본이 사용할 수 있는 형식으로 변환할 수 있습니다.

이 섹션에서는 VTL을 사용하여 해석기를 구성하는 방법을 보여 줍니다. 해석기 작성을 위한 입문용 자습서 스타일 프로그래밍 가이드는 [해석기 매핑 템플릿 프로그래밍 가이드](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide)에서 찾을 수 있으며 프로그래밍 시 사용할 수 있는 도우미 유틸리티는 [해석기 매핑 템플릿 컨텍스트 참조](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)에서 찾을 수 있습니다. AWS AppSync에는 처음부터 편집하거나 작성할 때 사용할 수 있는 테스트 및 디버그 흐름도 내장되어 있습니다. 자세한 내용은 [해석기 테스트 및 디버깅](test-debug-resolvers.md#aws-appsync-test-debug-resolvers)을 참조하세요.

앞서 언급한 자습서를 사용하기 전에 이 안내서를 확인하는 것이 좋습니다.

이 섹션에서는 해석기를 생성하고, 변형에 대해 해석기를 추가하고, 고급 구성을 사용하는 방법을 알아봅니다.

## 첫 번째 해석기 생성
<a name="create-your-first-resolver"></a>

이전 섹션의 예제에 따라 첫 번째 단계는 `Query` 유형에 맞는 해석기를 만드는 것입니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **스키마**를 선택합니다.

1. 페이지 오른쪽에 **해석기**라는 창이 있습니다. 이 상자에는 페이지 왼쪽의 **스키마** 창에 정의된 유형 및 필드 목록이 있습니다. 필드에 해석기를 연결할 수 있습니다. 예를 들어 **쿼리** 유형에서 `getTodos` 필드 옆에 있는 **첨부**를 선택합니다.

1. **해석기 생성** 페이지에서 [데이터 원본 연결](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) 안내서에서 만든 데이터 원본을 선택합니다. **매핑 템플릿 구성** 창에서 오른쪽의 드롭다운 목록을 사용하여 일반 요청 및 응답 매핑 템플릿을 모두 선택하거나 직접 작성할 수 있습니다.
**참고**  
요청 매핑 템플릿과 응답 매핑 템플릿의 쌍을 이루는 것을 단위 해석기라고 합니다. 단위 해석기는 일반적으로 기계적 작업을 수행하는 것이 목적이므로 데이터 원본 수가 적은 단일 작업에만 사용하는 것이 좋습니다. 더 복잡한 작업의 경우 여러 데이터 원본에서 순차적으로 여러 작업을 실행할 수 있는 파이프라인 해석기를 사용하는 것이 좋습니다.  
요청과 응답 매핑 템플릿의 차이점에 대한 자세한 정보는 [단위 해석기](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-mapping-template-reference-overview.html#unit-resolvers)를 참조하세요.  
파이프라인 해석기 사용에 대한 자세한 내용은 [파이프라인 해석기](pipeline-resolvers.md#aws-appsync-pipeline-resolvers)를 참조하세요.

1. 일반적인 사용 사례의 경우 AWS AppSync 콘솔에는 데이터 소스에서 항목(예: 모든 항목 쿼리, 개별 조회 등)을 가져오는 데 사용할 수 있는 템플릿이 내장되어 있습니다. 예를 들어 `getTodos`에 페이지 매김이 없는 [스키마 설계](designing-your-schema.md#aws-appsync-designing-your-schema)의 간단한 스키마 버전에서 항목을 나열하기 위한 요청 매핑 템플릿은 다음과 같습니다.

   ```
   {
       "version" : "2017-02-28",
       "operation" : "Scan"
   }
   ```

1. 요청과 동반되는 응답 매핑 템플릿은 항상 필요합니다. 콘솔은 다음과 같은 목록에 대한 패스스루 값과 함께 기본값을 제공합니다.

   ```
   $util.toJson($ctx.result.items)
   ```

   이 예제에서 항목의 목록에 대한 `context` 객체(별칭 `$ctx`)는 `$context.result.items` 양식을 갖습니다. GraphQL 작업이 단일 항목을 반환하는 경우가 됩니다`$context.result`. AWS AppSync는 이전에 나열된 함수와 같은 일반적인 작업에 대한 헬퍼 `$util.toJson` 함수를 제공하여 응답의 형식을 올바르게 지정합니다. 전체 함수 목록은 [해석기 매핑 템플릿 유틸리티 참조](resolver-util-reference.md#aws-appsync-resolver-mapping-template-util-reference)를 참조하세요.

1. **해석기 저장** 을 선택합니다.

------
#### [ API ]

1. [https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html) API를 호출하여 해석기 객체를 생성합니다.

1. [https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html) API를 호출하여 해석기의 필드를 수정할 수 있습니다.

------
#### [ CLI ]

1. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html) 명령을 실행하여 해석기를 생성합니다.

   이 특정 명령에 대해 6개의 파라미터를 입력해야 합니다.

   1. API의 `api-id`.

   1. 스키마에서 수정하려는 유형의 `type-name`. 콘솔 예제에서는 `Query`였습니다.

   1. 유형에서 수정하려는 필드의 `field-name`. 콘솔 예제에서는 `getTodos`였습니다.

   1. [데이터 원본 연결](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) 안내서에서 만든 데이터 원본의 `data-source-name`.

   1. 요청의 본문인 `request-mapping-template`. 콘솔 예제에서는 다음과 같았습니다.

      ```
      {
          "version" : "2017-02-28",
          "operation" : "Scan"
      }
      ```

   1. 응답의 본문인 `response-mapping-template`. 콘솔 예제에서는 다음과 같았습니다.

      ```
      $util.toJson($ctx.result.items)
      ```

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Query --field-name getTodos --data-source-name TodoTable --request-mapping-template "{ "version" : "2017-02-28", "operation" : "Scan", }" --response-mapping-template ""$"util.toJson("$"ctx.result.items)"
   ```

   CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

   ```
   {
       "resolver": {
           "kind": "UNIT",
           "dataSourceName": "TodoTable",
           "requestMappingTemplate": "{ version : 2017-02-28, operation : Scan, }",
           "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Query/resolvers/getTodos",
           "typeName": "Query",
           "fieldName": "getTodos",
           "responseMappingTemplate": "$util.toJson($ctx.result.items)"
       }
   }
   ```

1. 해석기의 필드 또는 매핑 템플릿을 수정하려면 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html) 명령을 실행합니다.

   `api-id` 파라미터를 제외하고 `create-resolver` 명령에 사용된 파라미터는 `update-resolver` 명령의 새 값으로 덮어써집니다.

------

## 변형에 대한 해석기 추가
<a name="adding-a-resolver-for-mutations"></a>

다음 단계는 `Mutation` 유형에 맞는 해석기를 생성하는 것입니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **스키마**를 선택합니다.

1. **변형** 유형에서 `addTodo` 필드 옆에 있는 **연결**을 선택합니다.

1. **해석기 생성** 페이지에서 [데이터 원본 연결](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) 안내서에서 만든 데이터 원본을 선택합니다.

1. DynamoDB에 새 항목을 추가하는 경우 요청 템플릿이 변형이므로 **매핑 템플릿 구성** 창에서 요청 템플릿을 수정해야 합니다. 다음 요청 매핑 템플릿을 사용합니다.

   ```
   {
       "version" : "2017-02-28",
       "operation" : "PutItem",
       "key" : {
           "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
       },
       "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
   }
   ```

1. AWS AppSync는 `addTodo` 필드에 정의된 인수를 GraphQL 스키마에서 DynamoDB 작업으로 자동 변환합니다. 이전 예에서는 변형 인수에서 전달된 `id`의 키를 `$ctx.args.id`로 사용하여 DynamoDB에 레코드를 저장합니다. 전달하는 다른 모든 필드는 `$util.dynamodb.toMapValuesJson($ctx.args)`을 사용하여 DynamoDB 특성에 자동으로 매핑됩니다.

   이 해석기의 경우 다음 응답 매핑 템플릿을 사용합니다.

   ```
   $util.toJson($ctx.result)
   ```

   AWS AppSync는 해석기 편집을 위한 테스트 및 디버그 워크플로도 지원합니다. 모의 `context` 객체를 사용하여 호출 전에 템플릿의 변환된 값을 확인할 수 있습니다. 선택적으로 쿼리를 실행할 때 대화식으로 데이터 원본에 대한 전체 요청 실행을 볼 수 있습니다. 자세한 내용은 [해석기 테스트 및 디버깅](test-debug-resolvers.md#aws-appsync-test-debug-resolvers) 및 [모니터링 및 로깅](monitoring.md#aws-appsync-monitoring)을 참조하세요.

1. **해석기 저장** 을 선택합니다.

------
#### [ API ]

[첫 번째 해석기 생성](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) 섹션의 명령과 이 섹션의 파라미터 세부 정보를 활용하여 API로 이 작업을 수행할 수도 있습니다.

------
#### [ CLI ]

[첫 번째 해석기 생성](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) 섹션의 명령과 이 섹션의 파라미터 세부 정보를 활용하여 CLI에서 이 작업을 수행할 수도 있습니다.

------

이 시점에서 고급 해석기를 사용하지 않는 경우 [API 사용](using-your-api.md#aws-appsync-using-your-api)에서 설명하는 것과 같이 GraphQL API 사용을 시작할 수 있습니다.

## 고급 해석기
<a name="advanced-resolvers"></a>

고급 섹션을 따르고 있으며, [스키마 설계](designing-your-schema.md#aws-appsync-designing-your-schema)의 샘플 스키마를 빌드하여 페이지 지정 스캔을 수행하는 경우 `getTodos` 필드에 대한 다음 요청 템플릿을 대신 사용합니다.

```
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": $util.defaultIfNull(${ctx.args.limit}, 20),
    "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null))
}
```

이러한 페이지 매김 사용 사례의 경우 응답 매핑에는 *커서*가 포함되어 있고(따라서 클라이언트가 다음에 시작할 페이지를 알 수 있음) 결과 집합이 포함되어 있어야 하기 때문에 응답 매핑은 단순한 패스스루 이상입니다. 매핑 템플릿은 다음과 같습니다.

```
{
    "todos": $util.toJson($context.result.items),
    "nextToken": $util.toJson($context.result.nextToken)
}
```

이전 응답 매핑 템플릿의 필드가 `TodoConnection` 형식에 정의된 필드와 일치해야 합니다.

`Comments` 테이블이 있고 `Todo` 형식에 대한 주석 필드를 해석하는 관계의 경우(`[Comment]`의 형식 반환) 두 번째 테이블을 기준으로 쿼리를 실행하는 매핑 템플릿을 사용할 수 있습니다. 이를 수행하려면 [데이터 원본 연결](attaching-a-data-source.md#aws-appsync-getting-started-build-a-schema-from-scratch)에서 설명하는 것과 같이 `Comments` 테이블에 대한 데이터 원본이 이미 생성되어야 합니다.

**참고**  
두 번째 테이블을 기준으로 쿼리 작업을 사용하는 것은 설명을 돕기 위한 목적일 뿐입니다. 대신 DynamoDB에 대해 다른 작업을 사용할 수 있습니다. 또한 관계는 GraphQL 스키마에 의해 제어되므로 AWS Lambda 또는 Amazon OpenSearch Service와 같은 다른 데이터 소스에서 데이터를 가져올 수 있습니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **스키마**를 선택합니다.

1. **Todo** 유형에서 `comments` 필드 옆에 있는 **연결**을 선택합니다.

1. **해석기 생성** 페이지에서 **주석** 테이블 데이터 원본을 선택합니다. 빠른 시작 안내서에서 **주석** 테이블의 기본 이름은 `AppSyncCommentTable`이지만, 지정한 이름에 따라 달라질 수 있습니다.

1. 요청 매핑 템플릿에 다음 스니펫을 추가합니다.

   ```
   {
       "version": "2017-02-28",
       "operation": "Query",
       "index": "todoid-index",
       "query": {
           "expression": "todoid = :todoid",
           "expressionValues": {
               ":todoid": {
                   "S": $util.toJson($context.source.id)
               }
           }
       }
   }
   ```

1. `context.source`는 해석 중인 현재 필드의 상위 객체를 참조합니다. 이 예제에서 `source.id`는 개별 `Todo` 객체를 참조하고, 이는 쿼리 표현식에 사용됩니다.

   다음과 같이 패스스루 응답 매핑 템플릿을 사용할 수 있습니다.

   ```
   $util.toJson($ctx.result.items)
   ```

1. **해석기 저장** 을 선택합니다.

1. 마지막으로 콘솔의 **스키마** 페이지로 돌아가서 `addComment` 필드에 해석기를 연결하고, `Comments` 테이블에 대한 데이터 원본을 지정합니다. 이 경우의 요청 매핑 템플릿은 인수로서 주석 처리된 특정 `todoid`가 포함된 단순한 `PutItem`이지만, `$utils.autoId()` 유틸리티를 사용하여 다음과 같이 주석에 대한 고유한 정렬 키를 생성할 수 있습니다.

   ```
   {
       "version": "2017-02-28",
       "operation": "PutItem",
       "key": {
           "todoid": { "S": $util.toJson($context.arguments.todoid) },
           "commentid": { "S": "$util.autoId()" }
       },
       "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
   }
   ```

   다음과 같이 패스스루 응답 템플릿을 사용합니다.

   ```
   $util.toJson($ctx.result)
   ```

------
#### [ API ]

[첫 번째 해석기 생성](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) 섹션의 명령과 이 섹션의 파라미터 세부 정보를 활용하여 API로 이 작업을 수행할 수도 있습니다.

------
#### [ CLI ]

[첫 번째 해석기 생성](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) 섹션의 명령과 이 섹션의 파라미터 세부 정보를 활용하여 CLI에서 이 작업을 수행할 수도 있습니다.

------

# 직접 Lambda 해석기(VTL)를 사용하여 VTL 매핑 템플릿 비활성화
<a name="direct-lambda-reference"></a>

**참고**  
이제는 APPSYNC\$1JS 런타임과 해당 문서를 주로 지원합니다. [여기](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)에서 APPSYNC\$1JS 런타임과 해당 안내서를 사용해 보세요.

직접 Lambda 해석기를 사용하면 AWS Lambda 데이터 소스를 사용할 때 VTL 매핑 템플릿 사용을 피할 수 있습니다. AWS AppSync는 Lambda 함수에 대한 기본 페이로드와 Lambda 함수의 응답에서 GraphQL 유형으로의 기본 변환을 제공할 수 있습니다. 요청 템플릿, 응답 템플릿을 제공하도록 선택할 수 있습니다. 그렇지 않으면 AWS AppSync가 이에 따라 처리하지 않습니다.

 AWS AppSync가 제공하는 기본 요청 페이로드 및 응답 변환에 대한 자세한 내용은 [Direct Lambda 해석기 참조](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers)를 참조하세요. AWS Lambda 데이터 소스 설정 및 IAM 신뢰 정책 설정에 대한 자세한 내용은 [데이터 소스 연결을 참조하세요](attaching-a-data-source.md).

## 직접 Lambda 해석기 구성
<a name="direct-lambda-reference-resolvers"></a>

다음 섹션에서는 Lambda 데이터 원본을 연결하고 Lambda 해석기를 필드에 추가하는 방법을 보여 줍니다.

### Lambda 데이터 원본 추가
<a name="direct-lambda-datasource"></a>

직접 Lambda 해석기를 활성화하려면 먼저 Lambda 데이터 원본을 추가해야 합니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **데이터 원본**을 선택합니다.

1. **데이터 원본 생성**을 선택합니다.

   1. **데이터 원본 이름**에 데이터 원본의 이름(예: **myFunction**)을 입력합니다.

   1. **데이터 원본 유형**에 **AWS Lambda 함수**를 선택합니다.

   1. **리전**에서 적절한 리전을 선택합니다.

   1. **함수 ARN**에는 드롭다운 목록에서 Lambda 함수를 선택합니다. 함수 이름을 검색하거나 사용하려는 함수의 ARN을 직접 입력할 수 있습니다.

   1. 새 IAM 역할을 만들거나(권장) `lambda:invokeFunction` IAM 권한이 있는 기존 역할을 선택합니다. 기존 역할에는 [데이터 원본 연결](attaching-a-data-source.md) 섹션에 설명된 대로 신뢰 정책이 필요합니다.

      다음은 리소스에서 작업을 수행하는 데 필요한 권한을 가진 IAM 정책의 예입니다.

------
#### [ JSON ]

****  

      ```
      { 
           "Version":"2012-10-17",		 	 	  
           "Statement": [ 
               { 
                   "Effect": "Allow", 
                   "Action": [ "lambda:invokeFunction" ], 
                   "Resource": [ 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction", 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction:*" 
                   ] 
               } 
           ] 
       }
      ```

------

1. **생성** 버튼을 선택합니다.

------
#### [ CLI ]

1. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html) 명령을 실행하여 데이터 원본 객체를 생성합니다.

   이 특정 명령에 대해 4개의 파라미터를 입력해야 합니다.

   1. API의 `api-id`.

   1. 데이터 원본의 `name`. 콘솔 예시에서는 **데이터 원본 이름**입니다.

   1. 데이터 원본의 `type`. 콘솔 예시에서는 **AWS Lambda 함수**입니다.

   1. `lambda-config`(콘솔 예시에서는 **함수 ARN**).
**참고**  
필수로 구성해야 하지만 일반적으로 CLI 구성 값으로 기본 설정되는 `Region`과 같은 다른 파라미터도 있습니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync create-data-source --api-id abcdefghijklmnopqrstuvwxyz --name myFunction --type AWS_LAMBDA --lambda-config lambdaFunctionArn=arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example
   ```

   CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

   ```
   {
       "dataSource": {
           "dataSourceArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/datasources/myFunction",
           "type": "AWS_LAMBDA",
           "name": "myFunction",
           "lambdaConfig": {
               "lambdaFunctionArn": "arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example"
           }
       }
   }
   ```

1. 데이터 원본의 특성을 수정하려면 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html) 명령을 실행합니다.

   `api-id` 파라미터를 제외하고 `create-data-source` 명령에 사용된 파라미터는 `update-data-source` 명령의 새 값으로 덮어써집니다.

------

### 직접 Lambda 해석기 활성화
<a name="direct-lambda-enable-templates"></a>

Lambda 데이터 소스를 생성하고 AWS AppSync가 함수를 호출할 수 있도록 적절한 IAM 역할을 설정한 후 해석기 또는 파이프라인 함수에 연결할 수 있습니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **스키마**를 선택합니다.

1. **해석기** 창에서 필드 또는 작업을 선택한 다음 **연결** 버튼을 선택합니다.

1. **새 해석기 생성** 페이지의 드롭다운 목록에서 Lambda 함수를 선택합니다.

1. 직접 Lambda 해석기를 활용하려면 **매핑 템플릿 구성** 섹션에서 요청 및 응답 매핑 템플릿이 비활성화되었는지 확인하세요.

1. **해석기 저장** 버튼을 선택합니다.

------
#### [ CLI ]
+ [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html) 명령을 실행하여 해석기를 생성합니다.

  이 특정 명령에 대해 6개의 파라미터를 입력해야 합니다.

  1. API의 `api-id`.

  1. 스키마에 있는 형식의 `type-name`.

  1. 스키마에 있는 필드의 `field-name`.

  1. `data-source-name` 또는 Lambda 함수의 이름.

  1. 요청의 본문인 `request-mapping-template`. 콘솔 예시에서는 이 파라미터가 비활성화되어 있었습니다.

     ```
     " "
     ```

  1. 응답의 본문인 `response-mapping-template`. 콘솔 예시에서는 이 파라미터도 비활성화되어 있었습니다.

     ```
     " "
     ```

  예를 들어 명령은 다음과 같을 수 있습니다.

  ```
  aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Subscription --field-name onCreateTodo --data-source-name LambdaTest --request-mapping-template " " --response-mapping-template " "
  ```

  CLI에서 출력이 반환됩니다. 다음은 그 예입니다.

  ```
  {
      "resolver": {
          "resolverArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/types/Subscription/resolvers/onCreateTodo",
          "typeName": "Subscription",
          "kind": "UNIT",
          "fieldName": "onCreateTodo",
          "dataSourceName": "LambdaTest"
      }
  }
  ```

------

매핑 템플릿을 비활성화하면 몇 가지 추가 동작이 AWS AppSync에서 발생합니다.
+ 매핑 템플릿을 비활성화하면 [Direct Lambda 해석기 참조](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers)에 지정된 기본 데이터 변환을 수락 AWS AppSync 한다는 신호를에 보냅니다.
+ 요청 매핑 템플릿을 비활성화하면 Lambda 데이터 원본이 전체 [컨텍스트](resolver-context-reference.md) 객체로 구성된 페이로드를 수신합니다.
+ 응답 매핑 템플릿을 비활성화하면 요청 매핑 템플릿의 버전 또는 요청 매핑 템플릿이 비활성화되었는지 여부에 따라 Lambda 간접 호출의 결과가 번역됩니다.

# AWS AppSync(VTL)에서 해석기 테스트 및 디버깅
<a name="test-debug-resolvers"></a>

**참고**  
이제 우리는 주로 APPSYNC\$1JS 런타임과 해당 문서를 지원합니다. [여기](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)에서 APPSYNC\$1JS 런타임과 해당 안내서를 사용해 보세요.

AWS AppSync는 데이터 소스에 대해 GraphQL 필드에서 해석기를 실행합니다. [해석기 매핑 템플릿 개요](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)에서 설명한 바와 같이, 해석기는 템플릿 언어를 사용하여 데이터 소스와 통신합니다. 이를 통해 데이터 소스와 통신하기 전과 후에 동작을 사용자 지정하고 로직 및 조건을 적용할 수 있습니다. 해석기 작성을 설명하는 소개 자습서 스타일의 프로그래밍 가이드는 [해석기 매핑 템플릿 프로그래밍 가이드](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide)를 참조하세요.

개발자가 이러한 해석기를 작성, 테스트 및 디버깅할 수 있도록 AWS AppSync 콘솔은 모의 데이터가 포함된 GraphQL 요청 및 응답을 개별 필드 해석기로 생성하는 도구도 제공합니다. 또한 AWS AppSync 콘솔에서 쿼리, 변형 및 구독을 수행하고 전체 요청에 대한 Amazon CloudWatch의 세부 로그 스트림을 볼 수 있습니다. 여기에는 데이터 원본의 결과가 포함됩니다.

## 모의 데이터를 사용하여 테스트
<a name="testing-with-mock-data"></a>

GraphQL 해석기가 호출되는 경우 이 해석기에는 요청에 대한 정보를 포함하는 `context` 객체가 들어 있습니다. 여기에는 클라이언트의 인수, 자격 증명 정보 및 상위 GraphQL 필드의 데이터가 포함됩니다. 또한 데이터 소스의 결과가 포함되며, 이러한 결과는 응답 템플릿에서 사용할 수 있습니다. 이 구조와 프로그래밍 시 사용할 수 있는 도우미 유틸리티에 대한 자세한 내용은 [해석기 매핑 템플릿 컨텍스트 참조](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference) 단원을 참조하세요.

해석기를 작성하거나 편집할 때 *mock* 또는 *test context* 객체를 콘솔 편집기로 전달할 수 있습니다. 이렇게 하면 데이터 원본에 대해 실행하지 않고도 요청과 응답 템플릿이 어떻게 평가되는지 알아볼 수 있습니다. 예를 들면 테스트 `firstname: Shaggy` 인수를 전달하고 템플릿 코드에서 `$ctx.args.firstname`을 사용하면 이 인수가 어떻게 평가되는지 볼 수 있습니다. 또한 `$util.autoId()` 또는 `util.time.nowISO8601()` 같은 유틸리티 도우미의 평가도 테스트할 수 있습니다.

### 해석기 테스트
<a name="test-a-resolver"></a>

이 예제에서는 AWS AppSync 콘솔을 사용하여 해석기를 테스트합니다.

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **스키마**를 선택합니다.

1. 아직 추가하지 않았다면 유형 아래 및 필드 옆에서 **첨부**를 선택하여 해석기를 추가합니다.

   완전한 해석기를 빌드하는 방법에 대한 자세한 내용은 [해석기 구성](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html)을 참조하세요.

   그렇지 않으면 필드에 이미 있는 해석기를 선택합니다.

1. **해석기 편집** 페이지 상단에서 **테스트 컨텍스트 선택**을 선택한 다음 **새 컨텍스트 생성**을 선택합니다.

1. 샘플 컨텍스트 객체를 선택하거나 아래 **실행 컨텍스트** 창에서 JSON을 수동으로 채웁니다.

1. **텍스트 컨텍스트 이름**에 입력합니다.

1. **저장** 버튼을 선택합니다.

1. **해석기 편집** 페이지 상단에서 **테스트 실행**을 선택합니다.

보다 실용적인 예로, 객체에 대한 자동 ID 생성을 사용하고 이를 Amazon DynamoDB에 저장하는 `Dog`의 GraphQL 유형을 저장하는 앱이 있다고 가정해 보겠습니다. 또한 GraphQL 변형의 인수에서 일부 값을 작성하고 특정 사용자만 응답을 볼 수 있도록 허용하려고 합니다. 스키마의 모양은 다음과 같을 수 있습니다.

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

`addDog` 뮤테이션의 해석기를 추가할 경우 다음의 예와 같이 컨텍스트 객체를 채울 수 있습니다. 다음 객체에는 `name` 및 `age` 클라이언트의 인수와 `identity` 객체에 채워진 `username`이 있습니다.

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

다음 요청과 응답 매핑 템플릿을 사용하여 이것을 테스트할 수 있습니다.

 **요청 템플릿** 

```
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "id" : { "S" : "$util.autoId()" }
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
```

 **응답 템플릿** 

```
#if ($context.identity.username == "Nadia")
  $util.toJson($ctx.result)
#else
  $util.unauthorized()
#end
```

평가된 템플릿에는 테스트 컨텍스트 객체의 데이터와 `$util.autoId()`에서 생성된 값이 포함됩니다. 또한, `username`을 `Nadia` 이외의 값으로 변경해야 했다면 권한 부여 확인이 실패하므로 결과가 반환되지 않습니다. 세분화된 액세스 제어에 대한 자세한 내용은 [권한 부여 사용 사례](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases) 단원을 참조하세요.

### AWS AppSync의 APIs를 사용하여 매핑 템플릿 테스트
<a name="testing-with-appsync-api"></a>

`EvaluateMappingTemplate` API 명령어를 사용하여 모의 데이터로 매핑 템플릿을 원격 테스트할 수 있습니다. 명령어를 시작하려면 정책에 `appsync:evaluateMappingTemplate` 권한을 추가했는지 확인하세요. 예제:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:evaluateMappingTemplate",
            "Resource": "arn:aws:appsync:us-east-1:111122223333:*"
        }
    ]
}
```

------

[AWS CLI](https://aws.amazon.com/cli/) 또는 [AWS SDK](https://aws.amazon.com/tools/)를 사용하여 명령을 활용할 수 있습니다. 예를 들어 이전 섹션의 `Dog` 스키마와 해당 요청/응답 매핑 템플릿을 가져옵니다. 로컬 스테이션에서 CLI를 사용하여 요청 템플릿을 `request.vtl`라는 파일에 저장한 다음 `context` 객체를 `context.json`이라는 파일에 저장합니다. 쉘에서 다음 명령을 실행합니다.

```
aws appsync evaluate-mapping-template --template file://request.vtl --context file://context.json
```

이 명령은 다음 응답을 반환합니다.

```
{
  "evaluationResult": "{\n    \"version\" : \"2017-02-28\",\n    \"operation\" : \"PutItem\",\n    \"key\" : {\n        \"id\" : { \"S\" : \"afcb4c85-49f8-40de-8f2b-248949176456\" }\n    },\n    \"attributeValues\" : {\"firstname\":{\"S\":\"Shaggy\"},\"age\":{\"N\":4}}\n}\n"
}
```

`evaluationResult`에는 제공된 `context`를 사용하여 제공된 템플릿을 테스트한 결과가 포함되어 있습니다. AWS SDKs. 다음은 AWS SDK for JavaScript V2를 사용하는 예제입니다.

```
const AWS = require('aws-sdk')
const client = new AWS.AppSync({ region: 'us-east-2' })

const template = fs.readFileSync('./request.vtl', 'utf8')
const context = fs.readFileSync('./context.json', 'utf8')

client
  .evaluateMappingTemplate({ template, context })
  .promise()
  .then((data) => console.log(data))
```

SDK를 사용하면 자주 사용하는 테스트 제품군의 테스트를 쉽게 통합하여 템플릿의 동작을 검증할 수 있습니다. [Jest 테스트 프레임워크](https://jestjs.io/)를 사용하여 테스트를 생성하는 것을 권장하지만, 어떤 테스트 도구도 사용 가능합니다. 다음 코드 조각은 가상의 검증 실행을 보여줍니다. 평가 응답은 유효한 JSON일 것으로 예상하므로 `JSON.parse`를 사용하여 문자열 응답에서 JSON을 검색합니다.

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })

test('request correctly calls DynamoDB', async () => {
  const template = fs.readFileSync('./request.vtl', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateMappingTemplate({ template, context }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 이 결과는 다음과 같아야 합니다.

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.511 s, estimated 2 s
```

## 라이브 쿼리 디버깅
<a name="debugging-a-live-query"></a>

프로덕션 애플리케이션을 디버깅하기 위한 end-to-end 테스트 및 로깅을 대체할 수 없습니다. AWS AppSync를 사용하면 Amazon CloudWatch를 사용하여 오류와 전체 요청 세부 정보를 로깅할 수 있습니다. 또한 AWS AppSync 콘솔을 사용하여 각 요청에 대한 GraphQL 쿼리, 변형 및 구독과 라이브 스트림 로그 데이터를 테스트하고 쿼리 편집기로 다시 전송하여 실시간으로 디버깅할 수 있습니다. 구독의 경우 로그는 연결-시간 정보를 표시합니다.

이를 수행하려면 [모니터링 및 로깅](monitoring.md#aws-appsync-monitoring)에 설명된 대로 Amazon CloudWatch 로그를 미리 활성화해야 합니다. 그런 다음 AWS AppSync 콘솔에서 **쿼리** 탭을 선택한 다음 유효한 GraphQL 쿼리를 입력합니다. 오른쪽 하단 섹션에서 **로그** 창을 클릭하고 드래그하여 로그 보기를 엽니다. 페이지 맨 위에 있는 ‘재생’ 화살표 아이콘을 선택하여 GraphQL 쿼리를 실행합니다. 몇 분 후 작업에 대한 전체 요청 및 응답 로그가 이 섹션으로 스트리밍되어 사용자가 콘솔에서 볼 수 있습니다.

# AWS AppSync(VTL)에서 파이프라인 해석기 구성 및 사용
<a name="pipeline-resolvers"></a>

**참고**  
이제 우리는 주로 APPSYNC\$1JS 런타임과 해당 문서를 지원합니다. [여기](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)에서 APPSYNC\$1JS 런타임과 해당 안내서를 사용해 보세요.

AWS AppSync는 GraphQL 필드에서 해석기를 실행합니다. 경우에 따라 애플리케이션 사용 시 단일 GraphQL 필드를 해석하기 위해 여러 작업을 실행해야 합니다. 이제, 파이프라인 해석기를 사용해 개발자는 함수라고 하는 작업을 작성하고 순서대로 실행할 수 있습니다. 파이프라인 해석기는 예를 들어, 필드에 필요한 데이터를 가져오기 전에 권한 부여를 확인해야 하는 애플리케이션에 유용합니다.

파이프라인 해석기는 **이전** 매핑 템플릿, **이후** 매핑 템플릿과 함수 목록으로 구성됩니다. 각 함수에는 데이터 원본에 대해 실행되는 **요청** 및 **응답** 매핑 템플릿이 있습니다. 파이프라인 해석기는 함수 목록에 실행을 위임하기 때문에 자신은 어떠한 데이터 원본에도 연결되지 않습니다. 단위 해석기와 함수는 데이터 원본에 대해 작업을 실행하는 기본 요소입니다. 자세한 내용은 [해석기 매핑 템플릿 개요](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)를 참조하세요.

## 1단계: 파이프라인 해석기 생성
<a name="create-a-pipeline-resolver"></a>

 AWS AppSync 콘솔에서 **스키마** 페이지로 이동합니다.

다음 스키마를 저장합니다.

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

type Mutation {
    signUp(input: Signup): User
}

type Query {
    getUser(id: ID!): User
}

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

**변형** 유형의 **signUp** 필드에 파이프라인 해석기를 연결하겠습니다. 오른쪽에 있는 **변형** 유형에서 `signUp` 변형 필드 옆에 있는 **연결**을 선택합니다. 해석기 생성 페이지에서 **작업**을 클릭한 다음 **런타임 업데이트**를 클릭합니다. `Pipeline Resolver`를 선택하고 `VTL`을 선택한 다음 **업데이트**를 선택합니다. 이 페이지에는 **사전 매핑 템플릿** 텍스트 영역, **함수** 섹션 및 **사후 매핑 템플릿** 텍스트 영역, 이렇게 3가지 섹션이 있어야 합니다.

파이프라인 해석기는 사용자를 등록해 먼저 입력된 이메일 주소를 확인한 다음 사용자를 시스템에 저장합니다. 이메일 검증을 **validateEmail** 함수 내에 캡슐화하고 사용자를 **saveUser** 함수 내에 저장할 것입니다. **validateEmail** 함수가 먼저 실행되고, 이메일이 유효한 경우 **saveUser** 함수가 실행됩니다.

다음과 같이 실행 흐름이 진행됩니다.

1. Mutation.signUp 해석기 요청 매핑 템플릿

1. validateEmail 함수

1. saveUser 함수

1. Mutation.signUp 해석기 응답 매핑 템플릿

API의 다른 해석기 내에서 **validateEmail** 함수를 다시 사용할 것입니다. GraphQL 필드 간에 변경되기 때문에 `$ctx.args`에는 액세스하지 않도록 하겠습니다. 대신 `$ctx.stash`를 사용해 `signUp(input: Signup)` 입력 필드 인수의 이메일 속성을 저장할 수 있습니다.

**사전** 매핑 템플릿:

```
## store email input field into a generic email key
$util.qr($ctx.stash.put("email", $ctx.args.input.email))
{}
```

콘솔은 사용할 기본 패스스루 **사후** 매핑 템플릿을 제공합니다.

```
$util.toJson($ctx.result)
```

**생성** 또는 **저장**을 선택하여 해석기를 업데이트합니다.

## 2단계: 함수 생성
<a name="create-a-function"></a>

파이프라인 해석기 페이지의 **함수** 섹션에서 **함수 추가**를 클릭하고 **새 함수 생성**을 클릭합니다. 해석기 페이지를 거치지 않고 함수를 생성할 수도 있습니다. 이렇게 하려면 AWS AppSync 콘솔에서 **함수** 페이지로 이동합니다. **함수 생성** 버튼을 선택합니다. 이메일이 유효하고 특정 도메인에서 전송되는지 확인하는 함수를 생성합니다. 이메일이 유효하지 않으면 함수에서 오류가 발생합니다. 이메일이 유효할 경우 제공된 입력을 전달합니다.

새 함수 페이지에서 **작업**을 선택한 다음 **런타임 업데이트**를 선택합니다. `VTL`을 선택하고 **업데이트**를 선택합니다. **없음** 유형의 데이터 원본을 생성했는지 확인합니다. **데이터 원본 이름** 목록에서 이 데이터 원본을 선택합니다. **함수 이름**에 `validateEmail`을 입력합니다. **함수 코드** 영역에서 다음 스니펫으로 모든 내용을 덮어씁니다.

```
#set($valid = $util.matches("^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com", $ctx.stash.email))
#if (!$valid)
    $util.error("$ctx.stash.email is not a valid email.")
#end
{
    "payload": { "email": $util.toJson(${ctx.stash.email}) }
}
```

이 내용을 응답 매핑 템플릿에 붙여넣습니다.

```
$util.toJson($ctx.result)
```

선택 항목을 검토한 다음 **생성**을 선택합니다. 방금 **validateEmail** 함수를 생성했습니다. 이 단계를 반복하여 다음 요청 및 응답 매핑 템플릿으로 **saveUser** 함수를 생성합니다(단순화를 위해 **없음** 데이터 원본을 사용하고 함수가 실행된 후 사용자가 시스템에 저장된 것으로 가장함).

요청 매핑 템플릿

```
## $ctx.prev.result contains the signup input values. We could have also
## used $ctx.args.input.
{
    "payload": $util.toJson($ctx.prev.result)
}
```

응답 매핑 템플릿:

```
## an id is required so let's add a unique random identifier to the output
$util.qr($ctx.result.put("id", $util.autoId()))
$util.toJson($ctx.result)
```

방금 **saveUser** 함수를 생성했습니다.

## 3단계: 파이프라인 해석기에 함수 추가
<a name="adding-a-function-to-a-pipeline-resolver"></a>

파이프라인 해석기에 방금 생성한 함수가 자동으로 추가되어야 합니다. 그렇지 않거나 **함수** 페이지를 통해 함수를 생성한 경우, 해석기 페이지에서 **함수 추가**를 클릭하여 연결할 수 있습니다. 해석기에 **validateEmail** 및 **saveUser** 함수를 모두 추가합니다. **validateEmail** 함수는 **saveUser** 함수 앞에 배치해야 합니다. 함수를 더 추가할 때 **위로 이동** 및 **아래로 이동** 옵션을 사용해 함수 실행 순서를 다시 정리할 수 있습니다. 변경 사항을 검토한 후 **저장**을 선택합니다.

## 4단계: 쿼리 실행
<a name="executing-a-query"></a>

 AWS AppSync 콘솔에서 **쿼리** 페이지로 이동합니다. 탐색기에서 변형을 사용하고 있는지 확인합니다. 그렇지 않다면 드롭다운 목록에서 `Mutation`을 선택한 다음 `+`를 선택합니다. 다음 쿼리를 입력합니다.

```
mutation {
  signUp(input: {
    email: "nadia@myvaliddomain.com"
    username: "nadia"
  }) {
    id
    email
  }
}
```

다음과 유사하게 반환되어야 합니다.

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "email": "nadia@myvaliddomain.com"
    }
  }
}
```

파이프라인 해석기를 사용하여 성공적으로 사용자를 등록했고, 입력한 이메일을 검증했습니다. 파이프라인 해석기에 대해 집중적으로 설명하는 자습서 전체를 살펴보려면 [자습서: 파이프라인 해석기](tutorial-pipeline-resolvers.md#aws-appsync-tutorial-pipeline-resolvers)를 참조하십시오.

# AWS CDK에서 AWS AppSync API 사용
<a name="using-your-api"></a>

**작은 정보**  
CDK를 사용하기 전에 CDK의 [공식 설명서](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html)와 [CDK 참조](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)를 검토 AWS AppSync하는 것이 좋습니다.  
또한 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 및 [NPM](https://docs.npmjs.com/) 설치가 시스템에서 작동하는지 확인하는 것이 좋습니다.

이 섹션에서는 DynamoDB 테이블에서 항목을 추가하고 가져올 수 있는 간단한 CDK 애플리케이션을 만듭니다. 이 예제는 [스키마 디자인](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html), [데이터 소스 연결](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html), [해석기 구성(JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html) 섹션의 일부 코드를 사용하는 빠른 시작 예제입니다.

## CDK 프로젝트 만들기
<a name="Setting-up-a-cdk-project"></a>

**주의**  
환경에 따라 이러한 단계가 완전히 정확하지 않을 수 있습니다. 시스템에 필요한 유틸리티, AWS 서비스와의 인터페이스 방법, 적절한 구성이 설치되어 있다고 가정합니다.

첫 번째 단계는 AWS CDK를 설치하는 것입니다. CLI에 다음 명령을 입력할 수 있습니다.

```
npm install -g aws-cdk
```

다음으로 프로젝트 디렉터리를 만든 다음 해당 디렉터리로 이동해야 합니다. 디렉터리를 만들고 탐색하기 위한 명령 세트의 예는 다음과 같습니다.

```
mkdir example-cdk-app
cd example-cdk-app
```

다음으로 앱을 만들어야 합니다. Amazon 서비스는 주로 TypeScript를 사용합니다. 프로젝트 디렉터리에서 다음 명령을 입력합니다.

```
cdk init app --language typescript
```

이렇게 하면 초기화 파일과 함께 CDK 앱이 설치됩니다.

![\[Terminal output showing Git repository initialization and npm install completion.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-init-app-example.png)


프로젝트 구조는 다음과 같습니다.

![\[Project directory structure showing folders and files for an example CDK app.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-init-directories.png)


다음과 같은 몇 가지 중요한 디렉토리가 있다는 것을 알 수 있습니다.
+ `bin`: 초기 bin 파일이 앱을 생성합니다. 이 안내서에서는 이 내용을 다루지 않겠습니다.
+ `lib`: lib 디렉토리에는 스택 파일이 들어 있습니다. 스택 파일은 개별 실행 단위로 생각할 수 있습니다. 구조는 스택 파일 안에 있을 것입니다. 기본적으로 이러한 리소스는 앱이 배포될 CloudFormation 때에서 스핀업되는 서비스의 리소스입니다. 대부분의 코딩이 이루어지는 곳입니다.
+ `node_modules`: 이 디렉터리는 NPM에서 생성하며 `npm` 명령을 사용하여 설치한 모든 패키지 종속성을 포함합니다.

초기 스택 파일에는 다음과 같은 내용이 포함될 수 있습니다.

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// import * as sqs from 'aws-cdk-lib/aws-sqs';

export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    // example resource
    // const queue = new sqs.Queue(this, 'ExampleCdkAppQueue', {
    //   visibilityTimeout: cdk.Duration.seconds(300)
    // });
  }
}
```

앱에서 스택을 생성하기 위한 보일러플레이트 코드입니다. 이 예제의 코드 대부분은 이 클래스의 범위에 속합니다.

스택 파일이 앱의 디렉터리에 있는지 확인하려면 터미널에서 다음 명령어를 실행합니다.

```
cdk ls
```

스택 목록이 표시되어야 합니다. 그렇지 않으면 단계를 다시 실행하거나 공식 설명서에서 도움을 받아야 할 수 있습니다.

배포하기 전에 코드 변경사항을 빌드하려면 언제든지 터미널에서 다음 명령을 실행하면 됩니다.

```
npm run build
```

그리고 배포하기 전에 변경 사항을 확인하는 방법은 다음과 같습니다.

```
cdk diff
```

스택 파일에 코드를 추가하기 전에 부트스트랩을 수행합니다. 부트스트래핑을 통해 앱을 배포하기 전에 CDK용 리소스를 프로비저닝할 수 있습니다. 이 프로세스에 대한 자세한 내용은 [여기](https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html)에서 확인할 수 있습니다. 부트스트랩을 생성하기 위한 명령은 다음과 같습니다.

```
cdk bootstrap aws://ACCOUNT-NUMBER/REGION
```

**작은 정보**  
이 단계를 수행하려면 계정에 여러 IAM 권한이 필요합니다. 권한이 없으면 부트스트랩이 거부됩니다. 이 경우 부트스트랩이 생성하는 S3 버킷과 같이 부트스트랩으로 인해 발생한 불완전한 리소스를 삭제해야 할 수도 있습니다.

부트스트랩은 여러 리소스를 가동합니다. 최종 메시지는 다음과 같습니다.

![\[Terminal output showing successful bootstrapping of an AWS environment.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-init-bootstrap-final.png)


이 작업은 리전별로 계정당 한 번 수행되므로 자주 수행하지 않아도 됩니다. 부트스트랩의 주요 리소스는 CloudFormation 스택과 Amazon S3 버킷입니다.

Amazon S3 버킷은 배포를 수행하는 데 필요한 권한을 부여하는 파일 및 IAM 역할을 저장하는 데 사용됩니다. 필요한 리소스는 일반적으로 이름이 인 부트스트랩 CloudFormation 스택이라는 스택에 정의됩니다`CDKToolkit`. CloudFormation 스택과 마찬가지로 배포되면 CloudFormation 콘솔에 표시됩니다.

![\[CDKToolkit stack with CREATE_COMPLETE status in CloudFormation console.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-init-bootstrap-cfn-console.png)


버킷도 마찬가지입니다.

![\[S3 bucket details showing name, region, access settings, and creation date.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-init-bootstrap-bucket-console.png)


스택 파일에서 필요한 서비스를 가져오려면 다음 명령을 사용할 수 있습니다.

```
npm install aws-cdk-lib # V2 command
```

**작은 정보**  
V2에 문제가 있는 경우 V1 명령을 사용하여 개별 라이브러리를 설치할 수 있습니다.  

```
npm install @aws-cdk/aws-appsync @aws-cdk/aws-dynamodb
```
V1은 더 이상 사용되지 않으므로 권장하지 않습니다.

## CDK 프로젝트 구현 - 스키마
<a name="implementing-a-cdk-project-schema"></a>

이제 코드 구현을 시작할 수 있습니다. 먼저 스키마를 만들어야 합니다. 앱에서 간단히 `.graphql` 파일을 만들 수 있습니다.

```
mkdir schema
touch schema.graphql
```

이 예제에서는 `schema`라는 최상위 디렉터리에 `schema.graphql`이 포함되어 있습니다.

![\[File structure showing a schema folder containing schema.graphql file.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-schema-directory.png)


스키마 안에 간단한 예제를 포함시켜 보겠습니다.

```
input CreatePostInput {
    title: String
    content: String
}

type Post {
    id: ID!
    title: String
    content: String
}

type Mutation {
    createPost(input: CreatePostInput!): Post
}

type Query {
    getPost: [Post]
}
```

스택 파일로 돌아가서 다음과 같은 가져오기 지시문이 정의되어 있는지 확인해야 합니다.

```
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
```

클래스 내에서 GraphQL API를 만드는 코드를 추가하고 `schema.graphql` 파일에 연결합니다.

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    // makes a GraphQL API
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });
  }
}
```

또한 GraphQL URL, API 키, 지역을 출력하는 코드를 추가할 예정입니다.

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

이제 앱 배포를 다시 사용하겠습니다.

```
cdk deploy
```

결과는 다음과 같습니다.

![\[Deployment output showing ExampleCdkAppStack details, including GraphQL API URL and stack region.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-schema.png)


이 예제는 성공한 것으로 보이지만 AWS AppSync 콘솔을 확인하여 다음을 확인해 보겠습니다.

![\[GraphQL interface showing successful API request with response data displayed.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-schema-result-1.png)


API가 생성된 것 같습니다. 이제 API에 연결된 스키마를 확인해 보겠습니다.

![\[GraphQL schema defining CreatePostInput, Post type, Mutation, and Query operations.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-schema-result-2.png)


이 코드가 스키마 코드와 일치하는 것 같으니 성공입니다. 메타데이터 관점에서 이를 확인하는 또 다른 방법은 CloudFormation 스택을 보는 것입니다.

![\[CloudFormation stack showing ExampleCdkAppStack update complete and CDKToolkit creation complete.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-schema-result-3.png)


CDK 앱을 배포하면 부트스트랩과 같은 리소스를 가동 CloudFormation 합니다. 앱 내의 각 스택은 CloudFormation 스택과 1:1로 매핑됩니다. 스택 코드로 돌아가면 클래스 이름 `ExampleCdkAppStack`에서 스택 이름을 가져왔습니다. GraphQL API 구조의 명명 규칙과 일치하는 리소스가 생성된 것을 확인할 수 있습니다.

![\[Expanded view of post-apis resource showing Schema, DefaultApiKey, and CDKMetadata.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-schema-result-4.png)


## CDK 프로젝트 구현 - 데이터 소스
<a name="implementing-a-cdk-project-data-source"></a>

다음으로 데이터 소스를 추가해야 합니다. 이 예제에서는 DynamoDB 테이블을 사용합니다. 스택 클래스 내에 새 테이블을 생성하는 코드를 몇 가지 추가해 보겠습니다.

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    //creates a DDB table
    const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
      partitionKey: {
        name: 'id',
        type: dynamodb.AttributeType.STRING,
      },
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

이제 다시 배포해 보겠습니다.

```
cdk deploy
```

DynamoDB 콘솔에서 새 테이블을 확인해야 합니다.

![\[DynamoDB console showing ExampleCdkAppStack-poststable as Active with Provisioned capacity.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-ddb-result-1.png)


스택 이름이 올바르고 테이블 이름이 코드와 일치합니다. CloudFormation 스택을 다시 확인하면 이제 새 테이블이 표시됩니다.

![\[Expanded view of a logical ID in CloudFormation showing post-apis, posts-table, and CDKMetadata.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-ddb-result-2.png)


## CDK 프로젝트 구현 - 해석기
<a name="implementing-a-cdk-project-resolver"></a>

이 예제에서는 두 개의 해석기를 사용합니다. 하나는 테이블을 쿼리하고 다른 하나는 테이블에 추가합니다. 파이프라인 해석기를 사용하고 있으므로 각각 함수가 하나씩 포함된 파이프라인 해석기 두 개를 선언해야 합니다. 쿼리에 다음 코드를 추가할 것입니다.

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    //creates a DDB table
    const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
      partitionKey: {
        name: 'id',
        type: dynamodb.AttributeType.STRING,
      },
    });

    // Creates a function for query
    const add_func = new appsync.AppsyncFunction(this, 'func-get-post', {
      name: 'get_posts_func_1',
      api,
      dataSource: api.addDynamoDbDataSource('table-for-posts', add_ddb_table),
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return { operation: 'Scan' };
          }

          export function response(ctx) {
          return ctx.result.items;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
    });

    // Creates a function for mutation
    const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', {
      name: 'add_posts_func_1',
      api,
      dataSource: api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table),
      code: appsync.Code.fromInline(`
          export function request(ctx) {
            return {
            operation: 'PutItem',
            key: util.dynamodb.toMapValues({id: util.autoId()}),
            attributeValues: util.dynamodb.toMapValues(ctx.args.input),
            };
          }

          export function response(ctx) {
            return ctx.result;
          }
      `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
    });

    // Adds a pipeline resolver with the get function
    new appsync.Resolver(this, 'pipeline-resolver-get-posts', {
      api,
      typeName: 'Query',
      fieldName: 'getPost',
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return {};
          }

          export function response(ctx) {
          return ctx.prev.result;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
      pipelineConfig: [add_func],
    });

    // Adds a pipeline resolver with the create function
    new appsync.Resolver(this, 'pipeline-resolver-create-posts', {
      api,
      typeName: 'Mutation',
      fieldName: 'createPost',
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return {};
          }

          export function response(ctx) {
          return ctx.prev.result;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
      pipelineConfig: [add_func_2],
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

이 코드 조각에는 `func-add-post`라는 함수가 첨부되어 호출되는 `pipeline-resolver-create-posts` 파이프라인 리졸버를 추가했습니다. 테이블에 `Posts`를 추가하는 코드입니다. 다른 파이프라인 해석기는 테이블에 추가된 `Posts`를 검색하는 `func-get-post`라는 함수가 있는 `pipeline-resolver-get-posts`라고 불렀습니다.

이를 배포하여 AWS AppSync 서비스에 추가합니다.

```
cdk deploy
```

 AWS AppSync 콘솔이 GraphQL API에 연결되어 있는지 확인해 보겠습니다.

![\[GraphQL API schema showing mutation and query fields with Pipeline resolvers.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-1.png)


맞는 것 같습니다. 코드에서 이 두 해석기는 모두 우리가 만든 GraphQL API에 연결되었습니다(해석기와 함수 모두에 있는 `api` 속성 값으로 표시됨). GraphQL API에서 해석기를 연결한 필드는 속성에도 지정되어 있습니다(각 해석기의 `typename` 및 `fieldname` 속성으로 정의됨).

`pipeline-resolver-get-posts`부터 해석기의 콘텐츠가 올바른지 확인해 보겠습니다.

![\[Code snippet showing request and response functions in a resolver, with an arrow pointing to them.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-2.png)


이전 핸들러와 이후 핸들러가 `code` 속성 값과 일치합니다. 또한 해석기에 연결된 함수 이름과 일치하는 `add_posts_func_1`이라는 함수가 있음을 알 수 있습니다.

해당 함수의 코드 내용을 살펴보겠습니다.

![\[Function code showing request and response methods for a PutItem operation.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-3.png)


이는 `add_posts_func_1` 함수의 `code` 속성과 일치합니다. 쿼리가 성공적으로 업로드되었으니 쿼리를 확인해 보겠습니다.

![\[Resolver code with request and response functions, and a get_posts_func_1 function listed below.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-4.png)


이것도 코드와 일치합니다. `get_posts_func_1`을 살펴보자면 다음과 같습니다.

![\[Code snippet showing two exported functions: request returning 'Scan' operation and response returning items.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-5.png)


모든 것이 제자리에 있는 것 같네요. 메타데이터 관점에서 이를 확인하기 위해 CloudFormation 에서 스택을 다시 확인할 수 있습니다.

![\[List of logical IDs for AWS resources including API, table, functions, and pipelines.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-6.png)


이제 몇 가지 요청을 수행하여 이 코드를 테스트해야 합니다.

## CDK 프로젝트 만들기 - 요청
<a name="implementing-a-cdk-project-requests"></a>

 AWS AppSync 콘솔에서 앱을 테스트하기 위해 쿼리 하나와 변형 하나를 만들었습니다.

![\[GraphQL code snippet showing a query to get post details and a mutation to create a post.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-request-1.png)


`MyMutation`에는 `1970-01-01T12:30:00.000Z` 및 `first post` 인수가 있는 `createPost` 작업이 포함됩니다. 자동으로 생성된 `id` 값뿐만 아니라 우리가 전달한 `date` 및 `title`을 반환합니다. 뮤테이션을 실행하면 다음과 같은 결과가 나옵니다.

```
{
  "data": {
    "createPost": {
      "date": "1970-01-01T12:30:00.000Z",
      "id": "4dc1c2dd-0aa3-4055-9eca-7c140062ada2",
      "title": "first post"
    }
  }
}
```

DynamoDB 테이블을 빠르게 확인하면 테이블을 스캔할 때 테이블에 있는 항목을 확인할 수 있습니다.

![\[DynamoDB table entry showing id, date, and title fields for a single item.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cdk-code-request-2.png)


 AWS AppSync 콘솔로 돌아가서 쿼리를 실행하여이를 검색하면 다음과 같은 결과가 나타납니다`Post`.

```
{
  "data": {
    "getPost": [
      {
        "id": "9f62c4dd-49d5-48d5-b835-143284c72fe0",
        "date": "1970-01-01T12:30:00.000Z",
        "title": "first post"
      }
    ]
  }
}
```

# 에서 실시간 데이터 애플리케이션에 구독 사용 AWS AppSync
<a name="aws-appsync-real-time-data"></a>

**중요**  
2025년 3월 13일부터 AWS AppSync 이벤트를 사용하여 WebSockets로 구동되는 실시간 PubSub API를 빌드할 수 있습니다. 자세한 내용은 *AWS AppSync 이벤트 개발자 안내서*의 [WebSocket을 통해 이벤트 게시](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html) 섹션을 참조하세요.

AWS AppSync를 사용하면 구독을 활용하여 라이브 애플리케이션 업데이트, 푸시 알림 등을 구현할 수 있습니다. 클라이언트가 GraphQL 구독 작업을 호출하면 AWS AppSync에서 보안 WebSocket 연결을 자동으로 설정하고 유지 관리합니다. 그러면 AWS AppSync가 애플리케이션의 연결 및 조정 요구 사항을 지속적으로 관리하는 동안 애플리케이션은 데이터 원본의 데이터를 구독자에게 실시간으로 배포할 수 있습니다. 다음 섹션에서는 AWS AppSync의 구독 작동 방식을 보여줍니다.

## GraphQL 스키마 구독 명령
<a name="graphql-schema-subscription-directives"></a>

 AWS AppSync의 구독은 변형에 대한 응답으로 호출됩니다. 즉, 변형에 GraphQL 스키마 명령을 지정하여 AWS AppSync에서 모든 데이터 소스를 실시간으로 만들 수 있습니다.

 AWS Amplify 클라이언트 라이브러리는 구독 연결 관리를 자동으로 처리합니다. 라이브러리는 순수 WebSocket을 클라이언트와 서비스 간의 네트워크 프로토콜로 사용합니다.

**참고**  
구독에 연결할 때 권한 부여를 제어하려면 필드 수준 권한 부여에 AWS Identity and Access Management (IAM), AWS Lambda Amazon Cognito 자격 증명 풀 또는 Amazon Cognito 사용자 풀을 사용할 수 있습니다. 구독에 대한 세분화된 액세스 제어를 위해 해석기를 구독 필드에 연결하고 호출자 및 AWS AppSync 데이터 소스의 ID를 사용하여 로직을 수행할 수 있습니다. 자세한 내용은 [GraphQL API를 보호하기 위한 권한 부여 및 인증 구성](security-authz.md) 단원을 참조하십시오.

구독이 변형에서 트리거되고 변형 선택 세트가 구독자에게 전송됩니다.

다음 예에서는 GraphQL 구독을 사용하는 방법을 보여 줍니다. 데이터 원본이 Lambda, Amazon DynamoDB 또는 Amazon OpenSearch Service일 수 있으므로 데이터 원본을 지정하지 않습니다.

구독으로 시작하려면 다음과 같이 스키마에 구독 진입점을 추가해야 합니다.

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

블로그 게시물 사이트가 있고 새 블로그와 기존 블로그에 대한 변경 사항을 구독하려 한다고 가정해 보겠습니다. 이를 수행하려면 스키마에 다음 `Subscription` 정의를 추가합니다.

```
type Subscription {
    addedPost: Post
    updatedPost: Post
    deletedPost: Post
}
```

다음과 같은 변형이 있다고 추가로 가정해 보겠습니다.

```
type Mutation {
    addPost(id: ID! author: String! title: String content: String url: String): Post!
    updatePost(id: ID! author: String! title: String content: String url: String ups: Int! downs: Int! expectedVersion: Int!): Post!
    deletePost(id: ID!): Post!
}
```

다음과 같이 알림을 받고자 하는 각 구독에 대해 `@aws_subscribe(mutations: ["mutation_field_1", "mutation_field_2"])` 명령을 추가하여 이러한 필드를 실시간으로 만들 수 있습니다.

```
type Subscription {
    addedPost: Post
    @aws_subscribe(mutations: ["addPost"])
    updatedPost: Post
    @aws_subscribe(mutations: ["updatePost"])
    deletedPost: Post
    @aws_subscribe(mutations: ["deletePost"])
}
```

`@aws_subscribe(mutations: ["",..,""])`는 변형 입력의 배열을 받기 때문에 구독을 시작하는 여러 변형을 지정할 수 있습니다. 클라이언트로부터 구독하는 경우, GraphQL 쿼리는 다음과 같습니다.

```
subscription NewPostSub {
    addedPost {
        __typename
        version
        title
        content
        author
        url
    }
}
```

이 구독 쿼리는 클라이언트 연결 및 도구에 필요합니다.

순수 WebSocket 클라이언트를 사용하는 경우 각 클라이언트가 자체 선택 세트를 정의할 수 있으므로 선택 세트 필터링은 클라이언트별로 수행됩니다. 이 경우 구독 선택 세트는 변형 선택 세트의 하위 집합이어야 합니다. 예를 들어 `addPost(...){id author title url version}` 변형과 연결된 `addedPost{author title}` 구독은 게시물의 작성자와 제목만 수신합니다. 다른 필드는 수신하지 않습니다. 그러나 변형의 선택 집합에 작성자가 없으면 구독자는 작성자 필드에 대한 `null` 값을 가져옵니다(작성자 필드가 스키마에서 필수/null이 아님으로 정의된 경우에는 오류를 가져옴).

순수 WebSocket을 사용할 때는 구독 선택 세트가 필수입니다. 필드가 구독에 명시적으로 정의되지 않은 경우는 필드를 반환 AWS AppSync 하지 않습니다.

이전 예제에서 구독에는 인수가 없었습니다. 스키마가 다음과 같은 모습이라고 가정합니다.

```
type Subscription {
    updatedPost(id:ID! author:String): Post
    @aws_subscribe(mutations: ["updatePost"])
}
```

이 경우 클라이언트는 구독을 다음과 같이 정의합니다.

```
subscription UpdatedPostSub {
    updatedPost(id:"XYZ", author:"ABC") {
        title
        content
    }
}
```

스키마에서 `subscription` 필드의 반환 형식은 해당 변형 필드의 반환 형식과 동일해야 합니다. 이전 예에서는 이러한 내용이 `addPost`와 `addedPost` 형식으로 반환된 `Post` 둘 다로 표시되었습니다.

클라이언트에 대한 구독을 설정하려면 [Amplify 클라이언트를 사용하여 클라이언트 애플리케이션 빌드](building-a-client-app.md) 섹션을 참조하세요.

## 구독 인수 사용
<a name="using-subscription-arguments"></a>

GraphQL 구독 사용 시 중요한 부분은 인수를 사용하는 시기와 방법을 이해하는 것입니다. 발생한 변형에 대해 클라이언트에게 알리는 방법과 시기를 세밀하게 수정할 수 있습니다. 이렇게 하려면 'Todos'를 생성하는 빠른 시작 장의 샘플 스키마를 참조하세요. 이 샘플 스키마에는 다음 변형이 정의되어 있습니다.

```
type Mutation {
    createTodo(input: CreateTodoInput!): Todo
    updateTodo(input: UpdateTodoInput!): Todo
    deleteTodo(input: DeleteTodoInput!): Todo
}
```

기본 샘플에서 클라이언트는 인수 없이 `onUpdateTodo` `subscription`을 사용하여 `Todo`에 대한 업데이트를 구독할 수 있습니다.

```
subscription OnUpdateTodo {
  onUpdateTodo {
    description
    id
    name
    when
  }
}
```

사용자는 해당 인수를 사용하여 `subscription`을 필터링할 수 있습니다. 예를 들어 특정 `ID`를 사용하는 `todo`가 업데이트될 때만 `subscription`을 트리거하려면 `ID` 값을 지정합니다.

```
subscription OnUpdateTodo {
  onUpdateTodo(id: "a-todo-id") {
    description
    id
    name
    when
  }
}
```

또한 여러 인수를 전달할 수도 있습니다. 예를 들어, 다음 `subscription`은 특정 장소와 시간에 `Todo` 업데이트에 대한 알림을 받는 방법을 보여 줍니다.

```
subscription todosAtHome {
  onUpdateTodo(when: "tomorrow", where: "at home") {
    description
    id
    name
    when
    where
  }
}
```

모든 인수는 선택 사항입니다. `subscription`에 인수를 지정하지 않으면 애플리케이션에서 발생하는 모든 `Todo` 업데이트를 구독하게 됩니다. 하지만 `ID` 인수가 필요하도록 `subscription`의 필드 정의를 업데이트할 수 있습니다. 이렇게 하면 모든 `todo`의 응답이 아닌 특정 `todo`의 응답이 발생합니다.

```
onUpdateTodo(
  id: ID!,
  name: String,
  when: String,
  where: String,
  description: String
): Todo
```

### 인수 null 값에는 의미가 있습니다.
<a name="argument-null-value-has-meaning"></a>

 AWS AppSync에서 구독 쿼리를 만들 때 `null` 인수 값은 인수를 완전히 생략하는 것과 다르게 결과를 필터링합니다.

todos를 생성할 수 있는 todos API 샘플로 돌아가 보겠습니다. 빠른 시작 장의 샘플 스키마를 참조하세요.

`Todo` 유형에 소유자를 설명하는 새 `owner` 필드를 포함하도록 스키마를 수정해 보겠습니다. `owner` 필드는 필수가 아니며 `UpdateTodoInput`에만 설정할 수 있습니다. 다음과 같은 스키마의 단순화된 버전을 참조하세요.

```
type Todo {
  id: ID!
  name: String!
  when: String!
  where: String!
  description: String!
  owner: String
}

input CreateTodoInput {
  name: String!
  when: String!
  where: String!
  description: String!
}

input UpdateTodoInput {
  id: ID!
  name: String
  when: String
  where: String
  description: String
  owner: String
}

type Subscription {
    onUpdateTodo(
        id: ID,
        name: String,
        when: String,
        where: String,
        description: String
    ): Todo @aws_subscribe(mutations: ["updateTodo"])
}
```

다음 구독은 모든 `Todo` 업데이트를 반환합니다.

```
subscription MySubscription {
  onUpdateTodo {
    description
    id
    name
    when
    where
  }
}
```

필드 인수 `owner: null`을 추가하도록 이전 구독을 수정하는 경우 이제 다른 질문을 하게 됩니다. 이제 이 구독은 소유자를 제공하지 않은 모든 `Todo` 업데이트에 대한 알림을 받을 수 있도록 클라이언트를 등록합니다.

```
subscription MySubscription {
  onUpdateTodo(owner: null) {
    description
    id
    name
    when
    where
  }
}
```

**참고**  
**2022년 1월 1일부터 WebSockets을 통한 MQTT는 더 이상 AWS AppSync APIs에서 GraphQL 구독의 프로토콜로 사용할 수 없습니다. 순수 WebSockets는에서 지원되는 유일한 프로토콜입니다 AWS AppSync.**  
2019년 11월 이후에 출시된 AWS AppSync SDK 또는 Amplify 라이브러리를 기반으로 하는 클라이언트는 기본적으로 순수 WebSockets을 자동으로 사용합니다. 클라이언트를 최신 버전으로 업그레이드하면 클라이언트가 AWS AppSync의 순수 WebSockets 엔진을 사용할 수 있습니다.  
순수 WebSocket은 더 큰 페이로드 크기(240KB), 더 다양한 클라이언트 옵션, 개선된 CloudWatch 메트릭을 제공합니다. 순수 WebSocket 사용 방법에 관한 추가 정보는 [ AWS AppSync에서 실시간 WebSocket 클라이언트 빌드](real-time-websocket-client.md) 섹션을 참조하세요.

# 에서 서버리스 WebSockets로 구동되는 일반 pub/sub APIs 생성 AWS AppSync
<a name="aws-appsync-real-time-create-generic-api-serverless-websocket"></a>

**중요**  
2025년 3월 13일부터 AWS AppSync 이벤트를 사용하여 WebSockets로 구동되는 실시간 PubSub API를 빌드할 수 있습니다. 자세한 내용은 *AWS AppSync 이벤트 개발자 안내서*의 [WebSocket을 통해 이벤트 게시](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html) 섹션을 참조하세요.

일부 애플리케이션에는 클라이언트가 특정 채널 또는 주제를 청취하는 단순한 WebSocket API만 필요합니다. 특정 형태나 엄격한 형식의 요구 사항이 없는 일반 JSON 데이터는 순수하고 단순한 게시-구독(pub/sub) 패턴으로 이러한 채널 중 하나를 청취하는 클라이언트에게 푸시할 수 있습니다.

 AWS AppSync를 사용하면 APIs 백엔드와 클라이언트 측 모두에서 GraphQL 코드를 자동으로 생성하여 몇 분 만에 GraphQL 지식이 거의 또는 전혀 없는 간단한 pub/sub WebSocket API를 구현할 수 있습니다.

## pub-sub API 생성 및 구성
<a name="aws-appsync-real-time-enhanced-filtering-using-pub-sub-apis"></a>

시작하려면 다음을 따르세요.

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **대시보드**에서 **API 생성**을 선택합니다.

1. 다음 화면에서 **실시간 API 생성**을 선택한 후 **다음**을 선택합니다.

1. pub/sub API에 대해 기억하기 쉬운 이름을 입력합니다.

1. [프라이빗 API](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html) 기능을 활성화할 수 있지만, 지금은 사용하지 않는 것이 좋습니다. **다음**을 선택합니다.

1. WebSocket을 사용하여 작동하는 pub/sub API를 자동으로 생성하도록 선택할 수 있습니다. 마찬가지로 지금은 이 기능도 사용하지 않는 것이 좋습니다. **다음**을 선택합니다.

1. **API 생성**을 선택한 다음 몇 분 정도 기다립니다. 계정에 사전 구성된 새로운 AWS AppSync pub/sub API가 생성됩니다 AWS .

API는 AWS AppSync의 내장 로컬 해석기(로컬 해석기 사용에 대한 자세한 내용은 *AWS AppSync 개발자 안내서*의 [자습서: 로컬 해석기](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-local-resolvers-js.html) 참조)를 사용하여 여러 임시 pub/sub 채널 및 WebSocket 연결을 관리합니다.이 연결은 채널 이름만을 기반으로 구독한 클라이언트에 데이터를 자동으로 전송하고 필터링합니다. API 직접 호출은 API 키로 권한이 부여됩니다.

API가 배포되면 클라이언트 코드를 생성하고 이를 클라이언트 애플리케이션과 통합하기 위한 몇 가지 추가 단계가 제공됩니다. 이 안내서에서는 클라이언트를 빠르게 통합하는 방법의 예로 간단한 React 웹 애플리케이션을 사용합니다.

1. 먼저 로컬 컴퓨터에서 [NPM](https://www.npmjs.com/get-npm)을 사용하여 보일러플레이트 React 앱을 만듭니다.

   ```
   $ npx create-react-app mypubsub-app 
   $ cd mypubsub-app
   ```
**참고**  
이 예제에서는 [Amplify 라이브러리](https://docs.amplify.aws/lib/)를 사용하여 클라이언트를 백엔드 API에 연결합니다. 하지만 Amplify CLI 프로젝트를 로컬에서 생성할 필요는 없습니다. 이 예제에서는 React를 클라이언트로 선택했지만 Amplify 라이브러리는 iOS, Android 및 Flutter 클라이언트도 지원하므로 서로 다른 런타임에서 동일한 기능을 제공합니다. 지원되는 Amplify 클라이언트는 AWS AppSync 실시간 WebSocket 프로토콜과 완벽하게 호환되는 내장 WebSocket 기능을 포함하여 몇 줄의 코드로 AppSync GraphQL API 백엔드와 상호 작용할 수 있는 간단한 추상화를 제공합니다. [AWS AppSync WebSocket ](https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html)  

   ```
   $ npm install @aws-amplify/api
   ```

1.  AWS AppSync 콘솔에서 **JavaScript**를 선택한 다음 **다운로드**를 선택하여 API 구성 세부 정보 및 생성된 GraphQL 작업 코드가 포함된 단일 파일을 다운로드합니다.

1. 다운로드한 파일을 React 프로젝트의 `/src` 폴더에 복사합니다.

1. 다음으로, 기존 보일러플레이트 `src/App.js` 파일의 내용을 콘솔에서 사용할 수 있는 샘플 클라이언트 코드로 대체합니다.

1. 다음 명령을 사용하여 로컬에서 애플리케이션을 시작합니다.

   ```
   $ npm start
   ```

1. 실시간 데이터 전송 및 수신을 테스트하려면 두 개의 브라우저 창을 열고 *localhost:3000*에 액세스하세요. 샘플 애플리케이션은 일반 JSON 데이터를 *robots*라는 하드 코딩된 채널로 전송하도록 구성되어 있습니다.

1.  브라우저 창 중 하나에서 텍스트 상자에 다음 JSON blob을 입력한 다음 **제출**을 클릭합니다.

   ```
   {
     "robot":"r2d2",
     "planet": "tatooine"
   }
   ```

두 브라우저 인스턴스 모두 *robots* 채널을 구독하며 게시된 데이터를 실시간으로 수신하여 웹 애플리케이션 하단에 표시합니다.

![\[pub/sub API용 React 앱 예시\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/pub-sub-react.png)


스키마, 해석기, 작업 등 필요한 모든 GraphQL API 코드가 자동으로 생성되어 일반 pub/sub 사용 사례를 지원합니다. 백엔드에서 데이터는 다음과 같은 GraphQL 변형을 사용하여 AWS AppSync의 실시간 엔드포인트에 게시됩니다.

```
mutation PublishData {
    publish(data: "{\"msg\": \"hello world!\"}", name: "channel") {
        data
        name
    }
}
```

구독자는 관련 GraphQL 구독을 통해 특정 임시 채널로 전송되는 게시된 데이터에 액세스합니다.

```
subscription SubscribeToData {
    subscribe(name:"channel") {
        name
        data
    }
}
```

## 기존 애플리케이션에 pub-sub API 구현
<a name="aws-appsync-real-time-enhanced-filtering-existing-apps"></a>

기존 애플리케이션에 실시간 기능을 구현해야 하는 경우 이 일반 pub/sub API 구성을 모든 애플리케이션 또는 API 기술에 쉽게 통합할 수 있습니다. 단일 API 엔드포인트를 사용하여 GraphQL을 사용한 단일 네트워크 호출에서 하나 이상의 데이터 소스의 데이터에 안전하게 액세스, 조작 및 결합하는 이점이 있지만 AWS , AppSync의 실시간 기능을 활용하기 위해 기존 REST 기반 애플리케이션을 처음부터 변환하거나 다시 빌드할 필요가 없습니다. 예를 들어, 실시간 및 pub/sub 목적으로만 기존 애플리케이션에서 일반 pub/sub API로 메시지나 이벤트를 보내고 받는 클라이언트가 있는 기존 CRUD 워크로드를 별도의 API 엔드포인트에 둘 수 있습니다.

# 에서 향상된 구독 필터 정의 AWS AppSync
<a name="aws-appsync-real-time-enhanced-filtering"></a>

**중요**  
2025년 3월 13일부터 AWS AppSync 이벤트를 사용하여 WebSockets로 구동되는 실시간 PubSub API를 빌드할 수 있습니다. 자세한 내용은 *AWS AppSync 이벤트 개발자 안내서*의 [WebSocket을 통해 이벤트 게시](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html) 섹션을 참조하세요.

에서는 추가 논리 연산자를 지원하는 필터를 사용하여 GraphQL API 구독 해석기에서 직접 백엔드의 데이터 필터링을 위한 비즈니스 로직을 정의하고 활성화 AWS AppSync할 수 있습니다. 클라이언트의 구독 쿼리에 정의된 구독 인수와는 다르게, 이러한 필터를 구성할 수 있습니다. 구독 인수 사용에 관한 자세한 정보는 [구독 인수 사용](aws-appsync-real-time-data.md#using-subscription-arguments) 섹션을 참조하세요. 연산자 목록은 [AWS AppSync 해석기 매핑 템플릿 유틸리티 참조](resolver-util-reference.md) 섹션을 참조하세요.

이 문서에서는 실시간 데이터 필터링을 다음과 같은 범주로 분류합니다.
+ **기본 필터링** - 구독 쿼리의 클라이언트 정의 인수를 기반으로 필터링합니다.
+ **향상된 필터링** - AWS AppSync 서비스 백엔드에서 중앙에 정의된 로직을 기반으로 필터링합니다.

다음 섹션에서는 향상된 구독 필터를 구성하는 방법을 설명하고 실제 사용 사례를 보여 줍니다.

## GraphQL 스키마에서 구독 정의
<a name="aws-appsync-real-time-enhanced-filtering-using-subscription-filters"></a>

향상된 구독 필터를 사용하려면 GraphQL 스키마에서 구독을 정의한 다음 필터링 확장을 사용하여 향상된 필터를 정의합니다. 향상된 구독 필터링이 작동하는 방식을 설명하려면 티켓 관리 시스템 API를 정의하는 다음 GraphQL 스키마를 예로 AWS AppSync들 수 있습니다.

```
type Ticket {
	id: ID
	createdAt: AWSDateTime
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	status: String
	
}

type Mutation {
	createTicket(input: TicketInput): Ticket
}

type Query {
	getTicket(id: ID!): Ticket
}

type Subscription {
	onSpecialTicketCreated: Ticket @aws_subscribe(mutations: ["createTicket"])
	onGroupTicketCreated(group: String!): Ticket @aws_subscribe(mutations: ["createTicket"])
}



enum Priority {
	none
	lowest
	low
	medium
	high
	highest
}

input TicketInput {
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
```

API용 `NONE` 데이터 원본을 만든 다음 이 데이터 원본을 사용하여 해석기를 `createTicket` 변형에 연결한다고 가정해 보겠습니다. 핸들러는 다음과 같을 수 있습니다.

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
	return {
		payload: {
			id: util.autoId(),
			createdAt: util.time.nowISO8601(),
			status: 'pending',
			...ctx.args.input,
		},
	};
}

export function response(ctx) {
	return ctx.result;
}
```

**참고**  
향상된 필터는 지정된 구독에서 GraphQL 해석기의 핸들러에 활성화됩니다. 자세한 내용은 [해석기 참조](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html)를 참조하세요.

향상된 필터의 동작을 구현하려면 `extensions.setSubscriptionFilter()` 함수를 사용하여 구독하는 클라이언트가 관심을 가질 수 있는 GraphQL 변형의 게시된 데이터에 대해 평가된 필터 식을 정의해야 합니다. 필터링 확장에 대한 자세한 내용은 [확장](https://docs.aws.amazon.com//appsync/latest/devguide/extensions-js.html)을 참조하세요.

다음 섹션에서는 필터링 확장을 사용하여 향상된 필터를 구현하는 방법을 설명합니다.

## 필터링 확장을 사용하여 향상된 구독 필터 생성
<a name="aws-appsync-real-time-enhanced-filtering-defining-filters"></a>

향상된 필터는 구독 해석기의 응답 핸들러에 JSON으로 작성됩니다. 필터는 `filterGroup`이라는 목록으로 그룹화할 수 있습니다. 필터는 각각 필드, 연산자 및 값이 있는 하나 이상의 규칙을 사용하여 정의됩니다. 향상된 필터를 설정하는 `onSpecialTicketCreated`에 대한 새 해석기를 정의해 보겠습니다. 하나의 필터는 AND 로직을 사용하여 평가되고, 필터 그룹의 여러 필터는 OR 로직을 사용하여 평가되는 여러 규칙을 구성할 수 있습니다.

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = {
		or: [
			{ severity: { ge: 7 }, priority: { in: ['high', 'medium'] } },
			{ category: { eq: 'security' }, group: { in: ['admin', 'operators'] } },
		],
	};
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

  // important: return null in the response
	return null;
}
```

이전 예제에 정의된 필터를 기반으로 다음을 사용하여 티켓을 만들면 중요한 티켓이 구독하는 API 클라이언트에게 자동으로 푸시됩니다.
+ `priority` 수준 `high` 또는 `medium`

  AND 
+ `severity` 수준이 `7`보다 크거나 같음(`ge`)

또는 
+ `classification` 티켓이 `Security`로 설정됨 

  AND 
+ `group` 할당이 `admin` 또는 `operators`로 설정됨

![\[티켓 필터링 쿼리를 보여주는 예시\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/aws-priority-example.png)


구독 해석기에 정의된 필터(향상된 필터링)는 구독 인수만을 기반으로 하는 필터링(기본 필터링)보다 우선합니다. 구독 인수 사용에 관한 자세한 정보는 [구독 인수 사용](https://docs.aws.amazon.com//appsync/latest/devguide/aws-appsync-real-time-data.html#using-subscription-arguments)을 참조하세요.

구독의 GraphQL 스키마에서 인수가 정의되고 필요한 경우 해당 인수가 해석기의 `extensions.setSubscriptionFilter()` 메서드에 규칙으로 정의된 경우에만 지정된 인수를 기반으로 필터링됩니다. 하지만 구독 해석기에 `extensions` 필터링 메서드가 없는 경우 클라이언트에 정의된 인수는 기본 필터링에만 사용됩니다. 기본 필터링과 향상된 필터링은 동시에 사용할 수 없습니다.

구독의 필터 확장 로직에 있는 [`context` 변수](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)를 사용하여 요청에 대한 컨텍스트 정보에 액세스할 수 있습니다. 예를 들어 권한 부여를 위해 Amazon Cognito 사용자 풀, OIDC 또는 Lambda 사용자 지정 권한 부여자를 사용하는 경우 구독이 설정되면 `context.identity`의 사용자에 대한 정보를 검색할 수 있습니다. 이 정보를 사용하여 사용자의 자격 증명을 기반으로 필터를 설정할 수 있습니다.

이제 `onGroupTicketCreated`에 대한 향상된 필터 동작을 구현한다고 가정해 보겠습니다. `onGroupTicketCreated` 구독에는 필수 `group` 이름이 인수로 필요합니다. 티켓을 만들면 티켓에 `pending` 상태가 자동으로 지정됩니다. 제공된 그룹에 속하는 새로 만들어진 티켓만 받도록 구독 필터를 설정할 수 있습니다.

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = { group: { eq: ctx.args.group }, status: { eq: 'pending' } };
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

	return null;
}
```

다음 예와 같이 변형을 사용하여 데이터를 게시하는 경우:

```
mutation CreateTicket {
  createTicket(input: {priority: medium, severity: 2, group: "aws"}) {
    id
    priority
    severity
    status
    group
    createdAt
  }
}
```

구독한 클라이언트는 `createTicket` 변형이 포함된 티켓이 생성되는 즉시 WebSocket을 통해 데이터가 자동으로 푸시되도록 수신 대기합니다.

```
subscription OnGroup {
  onGroupTicketCreated(group: "aws") {
    category
    status
    severity
    priority
    id
    group
    createdAt
    content
  }
}
```

필터링 로직은 향상된 필터링으로 AWS AppSync 서비스에 구현되어 클라이언트 코드를 간소화하므로 인수 없이 클라이언트를 구독할 수 있습니다. 클라이언트는 정의된 필터 기준을 충족하는 경우에만 데이터를 수신합니다.

## 중첩된 스키마 필드에 대한 향상된 필터 정의
<a name="aws-appsync-real-time-enhanced-filters-nested-schema-fields.title"></a>

향상된 구독 필터링을 사용하여 중첩된 스키마 필드를 필터링할 수 있습니다. 위치 및 주소 유형을 포함하도록 이전 섹션의 스키마를 수정했다고 가정해 보겠습니다.

```
type Ticket {
	id: ID
	createdAt: AWSDateTime
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	status: String
	location: ProblemLocation
}

type Mutation {
	createTicket(input: TicketInput): Ticket
}

type Query {
	getTicket(id: ID!): Ticket
}

type Subscription {
	onSpecialTicketCreated: Ticket @aws_subscribe(mutations: ["createTicket"])
	onGroupTicketCreated(group: String!): Ticket @aws_subscribe(mutations: ["createTicket"])
}

type ProblemLocation {
	address: Address
}

type Address {
	country: String
}

enum Priority {
	none
	lowest
	low
	medium
	high
	highest
}

input TicketInput {
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	location: AWSJSON
```

이 스키마에서는 `.` 구분 기호를 사용하여 중첩을 나타낼 수 있습니다. 다음 예제에서는 `location.address.country` 아래에 중첩된 스키마 필드에 대한 필터 규칙을 추가합니다. 티켓 주소가 `USA`로 설정되면 구독이 트리거됩니다.

```
import { util, extensions } from '@aws-appsync/utils';

export const request = (ctx) => ({ payload: null });

export function response(ctx) {
	const filter = {
		or: [
			{ severity: { ge: 7 }, priority: { in: ['high', 'medium'] } },
			{ category: { eq: 'security' }, group: { in: ['admin', 'operators'] } },
			{ 'location.address.country': { eq: 'USA' } },
		],
	};
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));
	return null;
}
```

위의 예에서 `location`은 중첩 수준 1을, `address`는 중첩 수준 2, `country`는 중첩 수준 3을 나타내며, 모두 `.` 구분 기호로 구분됩니다.

`createTicket` 변형을 사용하여 이 구독을 테스트할 수 있습니다.

```
mutation CreateTicketInUSA {
  createTicket(input: {location: "{\"address\":{\"country\":\"USA\"}}"}) {
    category
    content
    createdAt
    group
    id
    location {
      address {
        country
      }
    }
    priority
    severity
    status
  }
}
```

## 클라이언트에서 향상된 필터 정의
<a name="aws-appsync-real-time-enhanced-filtering-defining-from-client"></a>

GraphQL의 기본 필터링을 [구독 인수](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html#using-subscription-arguments)와 함께 사용할 수 있습니다. 구독 쿼리에서 호출을 수행하는 클라이언트가 인수 값을 정의합니다. `extensions` 필터링을 사용하여 AWS AppSync 구독 해석기에서 향상된 필터를 활성화하면 해석기에 정의된 백엔드 필터가 우선합니다.

구독의 `filter` 인수를 사용하여 동적 클라이언트 정의 향상된 필터를 구성하세요. 이러한 필터를 구성할 때는 새 인수를 반영하도록 GraphQL 스키마를 업데이트해야 합니다.

```
...
type Subscription {
    onSpecialTicketCreated(filter: String): Ticket
        @aws_subscribe(mutations: ["createTicket"])
}
...
```

그러면 클라이언트는 다음 예와 같이 구독 쿼리를 전송할 수 있습니다.

```
subscription onSpecialTicketCreated($filter: String) {
     onSpecialTicketCreated(filter: $filter) {
        id
        group
        description
        priority
        severity
     }
 }
```

다음 예와 같이 쿼리 변수를 구성할 수 있습니다.

```
{"filter" : "{\"severity\":{\"le\":2}}"}
```

구독 응답 매핑 템플릿에서 `util.transform.toSubscriptionFilter()` 해석기 유틸리티를 구현하여 구독 인수에 정의된 필터를 각 클라이언트의 적용할 수 있습니다.

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = ctx.args.filter;
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));
	return null;
}
```

이 전략을 통해 클라이언트는 향상된 필터링 로직과 추가 연산자를 사용하는 자체 필터를 정의할 수 있습니다. 지정된 클라이언트가 보안 WebSocket 연결에서 구독 쿼리를 간접적으로 호출하면 필터가 할당됩니다. `filter` 쿼리 변수 페이로드의 형식을 비롯하여 향상된 필터링을 위한 변환 유틸리티에 대한 자세한 내용은 [JavaScript 해석기 개요](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)를 참조하세요.

## 향상된 필터링 추가 제한 사항
<a name="aws-appsync-real-time-enhanced-filtering-additional-restrictions"></a>

다음은 향상된 필터에 추가 제한이 적용되는 몇 가지 사용 사례입니다.
+ 향상된 필터는 최상위 객체 목록에 대한 필터링을 지원하지 않습니다. 이 사용 사례에서는 향상된 구독을 위해 변형의 게시된 데이터가 무시됩니다.
+ AWS AppSync는 최대 5개의 중첩 수준을 지원합니다. 중첩 수준 5를 초과하는 스키마 필드에 대한 필터는 무시됩니다. 아래 GraphQL 응답을 예로 들어 보겠습니다. `venue.address.country.metadata.continent`의 `continent` 필드는 수준 5 중첩이므로 허용됩니다. 그러나 `venue.address.country.metadata.capital.financial`의 `financial`은 수준 6 중첩이므로 필터가 작동하지 않습니다.

  ```
  {
      "data": {
          "onCreateFilterEvent": {
              "venue": {
                  "address": {
                      "country": {
                          "metadata": {
                              "capital": {
                                  "financial": "New York"
                              },
                              "continent" : "North America"
                          }
                      },
                      "state": "WA"
                  },
                  "builtYear": 2023
              },
              "private": false,
          }
      }
  }
  ```

# 의 필터를 사용하여 WebSocket 연결 구독 취소 AWS AppSync
<a name="aws-appsync-real-time-invalidation"></a>

**중요**  
2025년 3월 13일부터 AWS AppSync 이벤트를 사용하여 WebSockets로 구동되는 실시간 PubSub API를 빌드할 수 있습니다. 자세한 내용은 *AWS AppSync 이벤트 개발자 안내서*의 [WebSocket을 통해 이벤트 게시](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html) 섹션을 참조하세요.

에서는 특정 필터링 로직을 기반으로 연결된 클라이언트에서 WebSocket 연결을 강제로 구독 취소하고 닫을 AWS AppSync수 있습니다(유효하지 않음). 이 기능은 그룹에서 사용자를 제거하는 경우와 같은 권한 부여 관련 시나리오에서 유용합니다.

구독 무효화는 변형에 정의된 페이로드에 대한 응답으로 발생합니다. 구독 연결을 무효화하는 데 사용되는 변형는 API의 관리 작업으로 취급하고 그에 따라 관리 사용자, 그룹 또는 백엔드 서비스로 사용을 제한하여 권한 범위를 지정하는 것이 좋습니다. 예를 들어 `@aws_auth(cognito_groups: ["Administrators"])` 또는 `@aws_iam`과 같은 스키마 권한 부여 지시문을 사용할 수 있습니다. 자세한 내용은 [추가 권한 부여 모드 사용](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html#using-additional-authorization-modes)을 참조하세요.

무효화 필터는 [향상된 구독 필터](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-enhanced-filtering.html)와 동일한 구문 및 로직을 사용합니다. 다음 유틸리티를 사용하여 이러한 필터를 정의하세요.
+ `extensions.invalidateSubscriptions()` - 변형에 대한 GraphQL 해석기의 응답 핸들러에서 정의됩니다.
+ `extensions.setSubscriptionInvalidationFilter()` - 변형에 연결된 구독의 GraphQL해석기의 응답 핸들러에서 정의됩니다.

무효화 필터링 확장에 대한 자세한 내용은 [JavaScript 해석기 개요](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)를 참조하세요.

## 구독 무효화 사용
<a name="aws-appsync-real-time-invalidation-using-invalidations"></a>

구독 무효화의 작동 방식을 확인하려면 다음 GraphQL 스키마를 AWS AppSync사용합니다.

```
type User {
  userId: ID!
  groupId: ID!
}
    
type Group {
  groupId: ID!
  name: String!
  members: [ID!]!
}

type GroupMessage {
  userId: ID!
  groupId: ID!
  message: String!
}

type Mutation {
    createGroupMessage(userId: ID!, groupId : ID!, message: String!): GroupMessage
    removeUserFromGroup(userId: ID!, groupId : ID!) : User @aws_iam
}

type Subscription {
    onGroupMessageCreated(userId: ID!, groupId : ID!): GroupMessage
        @aws_subscribe(mutations: ["createGroupMessage"])
}

type Query {
	none: String
}
```

`removeUserFromGroup` 변형 해석기 코드에서 무효화 필터를 정의하세요.

```
import { extensions } from '@aws-appsync/utils';

export function request(ctx) {
	return { payload: null };
}

export function response(ctx) {
	const { userId, groupId } = ctx.args;
	extensions.invalidateSubscriptions({
		subscriptionField: 'onGroupMessageCreated',
		payload: { userId, groupId },
	});
	return { userId, groupId };
}
```

변형이 간접적으로 호출되면 `subscriptionField`에 정의된 구독을 취소하는 데 `payload` 객체에 정의된 데이터가 사용됩니다. 무효화 필터는 `onGroupMessageCreated` 구독의 응답 매핑 템플릿에도 정의되어 있습니다.

필터에 정의된 대로 구독한 클라이언트의 ID와 일치하는 ID가 `extensions.invalidateSubscriptions()` 페이로드에 포함된 경우 해당 구독은 구독 취소됩니다. 또한 WebSocket 연결도 종료됩니다. `onGroupMessageCreated` 구독의 구독 해석기 코드를 정의하세요.

```
import { util, extensions } from '@aws-appsync/utils';

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = { groupId: { eq: ctx.args.groupId } };
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

	const invalidation = { groupId: { eq: ctx.args.groupId }, userId: { eq: ctx.args.userId } };
	extensions.setSubscriptionInvalidationFilter(util.transform.toSubscriptionFilter(invalidation));

	return null;
}
```

참고로 구독 응답 핸들러에는 구독 필터와 무효화 필터를 동시에 정의할 수 있습니다.

예를 들어 클라이언트 A가 다음 구독 요청을 사용하여 ID가 `group-1`인 그룹에 ID가 `user-1`인 새로운 사용자를 구독한다고 가정해 보겠습니다.

```
onGroupMessageCreated(userId : "user-1", groupId: :"group-1"){...}
```

AWS AppSync 는 이전 `onGroupMessageCreated` 응답 매핑 템플릿에 정의된 대로 구독 및 무효화 필터를 생성하는 구독 해석기를 실행합니다. 클라이언트 A의 경우 구독 필터는 데이터가 `group-1`로만 전송될 수 있게 하며, 무효화 필터는 `user-1` 및 `group-1` 모두에 대해 정의됩니다.

이제 클라이언트 B가 다음 구독 요청을 사용하여 ID가 `group-2`인 그룹에 ID가 `user-2`인 사용자를 구독한다고 가정해 보겠습니다.

```
onGroupMessageCreated(userId : "user-2", groupId: :"group-2"){...}
```

AWS AppSync 는 구독 및 무효화 필터를 생성하는 구독 해석기를 실행합니다. 클라이언트 B의 경우 구독 필터는 데이터가 `group-2`로만 전송될 수 있게 하며, 무효화 필터는 `user-2` 및 `group-2` 모두에 대해 정의됩니다.

다음으로, 다음 예와 같이 변형 요청을 사용하여 ID가 `message-1`인 새로운 그룹 메시지를 생성한다고 가정해 보겠습니다.

```
createGroupMessage(id: "message-1", groupId :
      "group-1", message: "test message"){...}
```

정의된 필터와 일치하는 구독 클라이언트는 WebSocket을 통해 다음 데이터 페이로드를 자동으로 수신합니다.

```
{
  "data": {
    "onGroupMessageCreated": {
      "id": "message-1",
      "groupId": "group-1",
      "message": "test message",
    }
  }
}
```

필터링 기준이 정의된 구독 필터와 일치하므로 클라이언트 A가 메시지를 수신합니다. 하지만 사용자가 `group-1`에 속하지 않으므로 클라이언트 B는 메시지를 수신하지 않습니다. 또한 요청이 구독 해석기에 정의된 구독 필터와 일치하지 않습니다.

마지막으로, 다음 변형 요청을 사용하여 `user-1`이 `group-1`에서 제거되었다고 가정해 보겠습니다.

```
removeUserFromGroup(userId: "user-1", groupId : "group-1"){...}
```

변형은 `extensions.invalidateSubscriptions()` 해석기 응답 핸들러 코드에 정의된 대로 구독 무효화를 시작한 AWS AppSync 다음 클라이언트 A의 구독을 취소하고 WebSocket 연결을 닫습니다. 변형에 정의된 무효화 페이로드가 해당 사용자 또는 그룹과 일치하지 않으므로 클라이언트 B는 영향을 받지 않습니다.

가 연결을 AWS AppSync 무효화하면 클라이언트는 구독이 취소되었음을 확인하는 메시지를 수신합니다.

```
{
  "message": "Subscription complete."
}
```

## 구독 무효화 필터에 컨텍스트 변수 사용
<a name="aws-appsync-real-time-invalidation-context"></a>

향상된 구독 필터와 마찬가지로 구독 무효화 필터 확장의 [`context` 변수](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)를 사용하여 특정 데이터에 액세스할 수 있습니다.

예를 들어, 이메일 주소를 변형의 무효화 페이로드로 구성한 다음 Amazon Cognito 사용자 풀 또는 OpenID Connect를 통해 권한이 부여된 구독 사용자의 이메일 특성 또는 클레임과 일치시킬 수 있습니다. `extensions.setSubscriptionInvalidationFilter()` 구독 무효 검증기에 정의된 무효화 필터는 변형의 `extensions.invalidateSubscriptions()` 페이로드에 의해 설정된 이메일 주소가 `context.identity.claims.email`에 있는 사용자의 JWT 토큰에서 검색된 이메일 주소와 일치하는지 확인하여 무효화를 시작합니다.

# AWS AppSync에서 실시간 WebSocket 클라이언트 빌드
<a name="real-time-websocket-client"></a>

**중요**  
2025년 3월 13일부터 AWS AppSync 이벤트를 사용하여 WebSockets로 구동되는 실시간 PubSub API를 빌드할 수 있습니다. 자세한 내용은 *AWS AppSync 이벤트 개발자 안내서*의 [WebSocket을 통해 이벤트 게시](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html) 섹션을 참조하세요.

AWS AppSync의 실시간 WebSocket 클라이언트는 다단계 프로세스를 통해 GraphQL 구독을 활성화합니다. 클라이언트는 먼저 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정하고 연결 초기화 메시지를 전송한 다음, 확인을 기다립니다. 연결에 성공하면 클라이언트는 고유한 IDs 및 GraphQL 쿼리로 시작 메시지를 전송하여 구독을 등록합니다. AWS AppSync는 승인 메시지로 성공적인 구독을 확인합니다. 그런 다음, 클라이언트는 해당 변형에서 트리거된 구독 이벤트를 수신합니다. 연결을 유지하기 위해 AWS AppSync는 주기적 연결 유지 메시지를 전송합니다. 기간이 종료되면 클라이언트는 중지 메시지를 전송하여 구독 등록을 취소합니다. 이 시스템은 단일 WebSocket 연결에서 여러 구독을 지원하며 API 키, Amazon Cognito 사용자 풀, IAM 및 Lambda를 비롯한 다양한 권한 부여 모드를 수용합니다.

## GraphQL 구독을 위한 실시간 WebSocket 클라이언트 구현
<a name="appsynclong-real-time-websocket-client-implementation-guide-for-graphql-subscriptions"></a>

다음 시퀀스 다이어그램 및 단계는 WebSocket 클라이언트, HTTP 클라이언트 및 AWS AppSync 간의 실시간 구독 워크플로를 보여줍니다.

![\[Sequence diagram showing WebSocket client, AppSync endpoints, and HTTP client interactions for real-time subscriptions.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/realtime-client-flow.png)


1. 클라이언트는 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정합니다. 네트워크 오류가 있는 경우 클라이언트는 지터 지수 백오프를 수행해야 합니다. 자세한 내용은 AWS 아키텍처 블로그의 [지수 백오프 및 지터](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)를 참조하세요.

1. (선택 사항) WebSocket 연결이 성공적으로 설정되면 클라이언트는 `connection_init` 메시지를 전송합니다.

1. `connection_init`가 전송되면 클라이언트는 AWS AppSync의 `connection_ack` 메시지를 기다립니다. 이 메시지에는 `"ka"`(연결 유지) 메시지의 최대 대기 시간(밀리초)인 `connectionTimeoutMs` 파라미터가 포함됩니다.

1. AWS AppSync는 주기적으로 `"ka"` 메시지를 전송합니다. 클라이언트는 각 `"ka"` 메시지를 수신한 시간을 추적합니다. 클라이언트가 `connectionTimeoutMs`밀리초 이내에 `"ka"` 메시지를 수신하지 못하면 클라이언트는 연결을 종료해야 합니다.

1. 클라이언트는 `start` 구독 메시지를 전송하여 구독을 등록합니다. 단일 WebSocket 연결은 서로 다른 인증 모드에 있더라도 여러 구독을 지원합니다.

1. 클라이언트는 AWS AppSync가 메시지를 보내 성공적인 구독`start_ack`을 확인할 때까지 기다립니다. 오류가 있는 경우 AWS AppSync는 `"type": "error"` 메시지를 반환합니다.

1. 클라이언트는 해당 변형이 직접적으로 호출된 후 전송되는 구독 이벤트를 수신합니다. 쿼리 및 변형은 일반적으로를 통해 AWS AppSync GraphQL 엔드포인트`https://`로 전송됩니다. 구독은 보안 WebSocket AWS ()을 사용하여 AppSync 실시간 엔드포인트를 통해 흐릅니다`wss://`.

1. 클라이언트는 `stop` 구독 메시지를 전송하여 구독을 등록 취소합니다.

1. 모든 구독을 등록 취소하고 WebSocket을 통해 전송되는 메시지가 없는지 확인한 후, 클라이언트는 WebSocket 연결에서 연결을 해제할 수 있습니다.

## WebSocket 연결을 설정하기 위한 핸드셰이크 세부 정보
<a name="handshake-details-to-establish-the-websocket-connection"></a>

 AWS AppSync를 사용하여 성공적인 핸드셰이크를 연결하고 시작하려면 WebSocket 클라이언트에 다음이 필요합니다.
+  AWS AppSync 실시간 엔드포인트
+ 헤더 - AWS AppSync 엔드포인트 및 권한 부여와 관련된 정보를 포함합니다. AWS AppSync는 헤더를 제공하는 다음 세 가지 방법을 지원합니다.
  + 쿼리 문자열을 통한 헤더
    + 헤더 정보는 문자열화된 JSON 객체에서 파생된 base64 문자열로 인코딩됩니다. 이 JSON 객체에는 AWS AppSync 엔드포인트 및 권한 부여와 관련된 세부 정보가 포함되어 있습니다. JSON 객체 내용은 권한 부여 모드에 따라 다릅니다.
  + `Sec-WebSocket-Protocol`을 통한 헤더
    +  AWS AppSync 엔드포인트 및 권한 부여와 관련된 정보가 포함된 문자열화된 JSON 객체의 base64Url-encoded 문자열이 `Sec-WebSocket-Protocol` 헤더의 프로토콜로 전달됩니다. JSON 객체 내용은 권한 부여 모드에 따라 다릅니다.
  + 표준 HTTP 헤더를 통한 헤더:
    + 헤더는 GraphQL 쿼리 및 변형에 대해 헤더가 AWS AppSync에 전달되는 방식과 마찬가지로 연결 요청에서 표준 HTTP 헤더로 전달될 수 있습니다. 그러나 프라이빗 API 연결 요청에는 표준 HTTP 헤더를 통한 헤더 전달이 지원되지 않습니다.
+  `payload` - `payload`의 Base64로 인코딩된 문자열입니다. 페이로드는 쿼리 문자열을 사용하여 헤더가 제공된 경우에만 필요합니다.

WebSocket 클라이언트는 이러한 요구 사항과 함께 `graphql-ws`를 WebSocket 프로토콜로 사용하여 쿼리 문자열이 있는 API 실시간 엔드포인트가 포함된 URL에 연결할 수 있습니다.

### GraphQL 엔드포인트에서 실시간 엔드포인트 검색
<a name="discovering-the-appsync-real-time-endpoint-from-the-appsync-graphql-endpoint"></a>

 AWS AppSync GraphQL 엔드포인트와 AWS AppSync 실시간 엔드포인트는 프로토콜과 도메인에서 약간 다릅니다. AWS Command Line Interface (AWS CLI) 명령를 사용하여 GraphQL 엔드포인트를 검색할 수 있습니다`aws appsync get-graphql-api`.

****AWS AppSync GraphQL 엔드포인트:****  
 `https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql`

****AWS AppSync 실시간 엔드포인트:****  
 `wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql`

애플리케이션은 쿼리 및 변형에 대해 모든 HTTP 클라이언트를 사용하여 AWS AppSync GraphQL 엔드포인트(`https://`)에 연결할 수 있습니다. 애플리케이션은 구독용 WebSocket AWS 클라이언트를 사용하여 AppSync 실시간 엔드포인트(`wss://`)에 연결할 수 있습니다.

사용자 지정 도메인 이름을 사용하면 하나의 도메인을 사용하여 두 엔드포인트와 모두 상호 작용할 수 있습니다. 예를 들어 `api.example.com`을 사용자 지정 도메인으로 구성하면 다음 URL을 사용하여 GraphQL 및 실시간 엔드포인트와 상호 작용할 수 있습니다.

**AWS AppSync 사용자 지정 도메인 GraphQL 엔드포인트:**  
`https://api.example.com/graphql`

**AWS AppSync 사용자 지정 도메인 실시간 엔드포인트:**  
`wss://api.example.com/graphql/realtime`

## AWS AppSync API 권한 부여 모드를 기반으로 하는 헤더 파라미터 형식
<a name="header-parameter-format-based-on-appsync-api-authorization-mode"></a>

연결 쿼리 문자열에 사용되는 `header` 객체의 형식은 AWS AppSync API 권한 부여 모드에 따라 다릅니다. 객체의 `host` 필드는 실시간 엔드포인트에 대해 `wss://` 호출이 이루어진 경우에도 연결을 검증하는 데 사용되는 AWS AppSync GraphQL 엔드포인트를 나타냅니다. 핸드셰이크를 시작하고 인증된 연결을 설정하려면 `payload`가 비어 있는 JSON 객체여야 합니다. 페이로드는 헤더가 쿼리 문자열을 통해 전달되는 경우에만 필요합니다.

다음 섹션에서는 각 권한 부여 모드의 헤더 형식을 보여줍니다.

### API 키
<a name="api-key"></a>

#### API 키 헤더
<a name="api-key-list"></a>

**헤더 콘텐츠**
+  `"host": <string>`: AWS AppSync GraphQL 엔드포인트의 호스트 또는 사용자 지정 도메인 이름입니다.
+  `"x-api-key": <string>`: AWS AppSync API에 대해 구성된 API 키입니다.

**예제**

```
{
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com",
    "x-api-key":"da2-12345678901234567890123456"
}
```

**쿼리 문자열을 통한 헤더**

먼저 `host` 및 `x-api-key`를 포함하는 JSON 객체가 문자열로 변환됩니다. 다음으로 이 문자열은 base64 인코딩을 사용하여 인코딩됩니다. 결과 base64 인코딩 문자열은 AWS AppSync 실시간 엔드포인트와의 연결을 설정`header`하기 위해 WebSocket URL에 라는 쿼리 파라미터로 추가됩니다. WebSocket 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJob3N0IjoiZXhhbXBsZTEyMzQ1Njc4OTAwMDAuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20iLCJ4LWFtei1kYXRlIjoiMjAyMDA0MDFUMDAxMDEwWiIsIngtYXBpLWtleSI6ImRhMi16NHc0NHZoczV6Z2MzZHRqNXNranJsbGxqaSJ9&payload=e30=
```

base64로 인코딩된 헤더 객체 외에도 빈 JSON 객체 \$1\$1도 base64로 인코딩되어 WebSocket URL에 `payload`로 명명된 별도의 쿼리 파라미터로 포함됩니다.

**`Sec-WebSocket-Protocol`을 통한 헤더**

`host` 및 `x-api-key`를 포함하는 JSON 객체는 문자열로 변환된 다음 base64Url 인코딩을 사용하여 인코딩됩니다. 결과 base64Url-encoded 문자열에는 접두사 `header-`가 붙습니다. 그런 다음 접두사가 붙은이 문자열은 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 `Sec-WebSocket-Protocol` 헤더`graphql-ws`에 외에도 새 하위 프로토콜로 사용됩니다.

결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 헤더에는 다음 값이 포함됩니다.

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**표준 HTTP 헤더를 통한 헤더**

이 방법에서 호스트 및 API 키 정보는 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 표준 HTTP 헤더를 사용하여 전송됩니다. 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

요청 헤더에 다음이 포함될 수 있습니다.

```
"sec-websocket-protocol" : ["graphql-ws"]
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com",
"x-api-key":"da2-12345678901234567890123456"
```

### Amazon Cognito 사용자 풀 및 OpenID Connect(OIDC)
<a name="amazon-cognito-user-pools-and-openid-connect-oidc"></a>

#### Amazon Cognito 및 OIDC 헤더
<a name="amazon-cognito-user-pools-and-openid-connect-oidc-list"></a>

헤더 콘텐츠:
+  `"Authorization": <string>`: JWT ID 토큰입니다. 헤더는 [보유자 체계](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1)를 사용할 수 있습니다.
+  `"host": <string>`: AWS AppSync GraphQL 엔드포인트의 호스트 또는 사용자 지정 도메인 이름입니다.

예제:

```
{
    "Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
}
```

**쿼리 문자열을 통한 헤더**

먼저 `host` 및 `Authorization`를 포함하는 JSON 객체가 문자열로 변환됩니다. 다음으로 이 문자열은 base64 인코딩을 사용하여 인코딩됩니다. 결과 base64 인코딩 문자열은 AWS AppSync 실시간 엔드포인트와의 연결을 설정`header`하기 위해 WebSocket URL에 라는 쿼리 파라미터로 추가됩니다. WebSocket 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

base64로 인코딩된 헤더 객체 외에도 빈 JSON 객체 \$1\$1도 base64로 인코딩되어 WebSocket URL에 `payload`로 명명된 별도의 쿼리 파라미터로 포함됩니다.

**`Sec-WebSocket-Protocol`을 통한 헤더**

`host` 및 `Authorization`를 포함하는 JSON 객체는 문자열로 변환된 다음 base64Url 인코딩을 사용하여 인코딩됩니다. 결과 base64Url-encoded 문자열에는 접두사 `header-`가 붙습니다. 그런 다음 접두사가 붙은이 문자열은 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 `Sec-WebSocket-Protocol` 헤더`graphql-ws`에 외에도 새 하위 프로토콜로 사용됩니다.

결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 헤더에는 다음 값이 포함됩니다.

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**표준 HTTP 헤더를 통한 헤더**

이 방법에서 호스트 및 권한 부여 정보는 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 표준 HTTP 헤더를 사용하여 전송됩니다. 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

요청 헤더에 다음이 포함될 수 있습니다.

```
"sec-websocket-protocol" : ["graphql-ws"]
"Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
```

### IAM
<a name="iam"></a>

#### IAM 헤더
<a name="iam-list"></a>

**헤더 콘텐츠**
+  `"accept": "application/json, text/javascript"`: 상수 `<string>` 파라미터입니다.
+  `"content-encoding": "amz-1.0"`: 상수 `<string>` 파라미터입니다.
+  `"content-type": "application/json; charset=UTF-8"`: 상수 `<string>` 파라미터입니다.
+  `"host": <string>`: AWS AppSync GraphQL 엔드포인트의 호스트입니다.
  + `"x-amz-date": <string>`: 타임스탬프는 협정 세계시(UTC)이고 YYYYMMDD'T'HHMMSS'Z' ISO 8601 형식이어야 합니다. 예를 들어, 20150830T123600Z는 유효한 타임스탬프입니다. 타임스탬프에 밀리초를 포함하지 마십시오. 자세한 정보는 *AWS 일반 참조*의 [서명 버전 4에서 날짜 처리](https://docs.aws.amazon.com/general/latest/gr/sigv4-date-handling.html)를 참조하세요.
  +  `"X-Amz-Security-Token": <string>`: 임시 보안 자격 증명을 사용할 때 필요한 AWS 세션 토큰입니다. 자세한 내용은 IAM 사용 설명서의 [AWS  리소스에서 임시 보안 인증 사용](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_credentials_temp_use-resources.html)**을 잠조하세요.
  +  `"Authorization": <string>`: AWS AppSync 엔드포인트에 대한 Signature Version 4(SigV4) 서명 정보입니다. 서명 프로세스에 대한 자세한 내용은 *AWS 일반 참조*의 [작업 4: HTTP 요청에 서명 추가](https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html)를 참조하세요.

SigV4 서명 HTTP 요청에는 표준 URL이 포함되며, 이 URL은 `/connect`가 추가된 AWS AppSync GraphQL 엔드포인트입니다. 서비스 엔드포인트 AWS 리전은 AWS AppSync API를 사용하는 리전과 동일하며 서비스 이름은 'appsync'입니다. 서명할 HTTP 요청은 다음과 같습니다.

```
{
  url: "https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql/connect",
  data: "{}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

**예제**

```
{
  "accept": "application/json, text/javascript",
  "content-encoding": "amz-1.0",
  "content-type": "application/json; charset=UTF-8",
  "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
  "x-amz-date": "20200401T001010Z",
  "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
  "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
}
```

**쿼리 문자열을 통한 헤더**

먼저 `host` (AWS AppSync GraphQL 엔드포인트) 및 기타 권한 부여 헤더가 포함된 JSON 객체가 문자열로 변환됩니다. 다음으로 이 문자열은 base64 인코딩을 사용하여 인코딩됩니다. 결과 base64 인코딩 문자열은 WebSocket URL에 `header`로 명명된 쿼리 파라미터로 추가됩니다. 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

base64로 인코딩된 헤더 객체 외에도 빈 JSON 객체 \$1\$1도 base64로 인코딩되어 WebSocket URL에 `payload`로 명명된 별도의 쿼리 파라미터로 포함됩니다.

**`Sec-WebSocket-Protocol`을 통한 헤더**

`host` 및 기타 권한 부여 헤더가 포함된 JSON 객체는 문자열로 변환된 다음 base64Url 인코딩을 사용하여 인코딩됩니다. 결과 base64Url-encoded 문자열에는 접두사 `header-`가 붙습니다. 그런 다음 접두사가 붙은이 문자열은 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 `Sec-WebSocket-Protocol` 헤더`graphql-ws`에 외에도 새 하위 프로토콜로 사용됩니다.

결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 헤더에는 다음 값이 포함됩니다.

```
"sec-websocket-protocol" : ["graphql-ws", "header-ew0KICAiYWNjZXB0IjogImFwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2YXNjcmlwdCIsDQogICJjb250ZW50LWVuY29kaW5nIjogImFtei0xLjAiLA0KICAiY29udGVudC10eXBlIjogImFwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9VVRGLTgiLA0KICAiaG9zdCI6ICJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsDQogICJ4LWFtei1kYXRlIjogIjIwMjAwNDAxVDAwMTAxMFoiLA0KICAiWC1BbXotU2VjdXJpdHktVG9rZW4iOiAiQWdFWEFNUExFWjJsdVgyVmpFQW9hRG1Gd0xYTnZkWFJvWldGRVhBTVBMRWN3UlFJZ0FoOTdDbGpxN3dPUEw4S3N4UDNZdER1eWMvOWhBajhQaEo3RnZmMzhTZ29DSVFEaEpFWEFNUExFUHNwaW9PenRqKytwRWFnV0N2ZVpVaktFbjB6eVVoQkVYQU1QTEVqai8vLy8vLy8vLy84QkVYQU1QTEV4T0RrMk5EZ3lOemcxTlNJTW8xbVducEVTV1VvWXc0QmtLcUVGU3JtM0RYdUw4dytaYlZjNEpLakRQNHZVQ0tOUjZMZTlDOXBacDlQc1cwTm9GeTN2TEJVZEFYRVhBTVBMRU9WRzhmZVhmaUVFQSsxa2hnRksvd0V0d1IrOXpGN05hTU1Nc2UwN3dOMmdHMnRIMGVLTUVYQU1QTEVRWCtzTWJ5dFFvOGllcFA5UFpPemxac1NGYi9kUDVROGhrNllFWEFNUExFWWNLWnNUa0RBcTJ1S0ZROG1ZVVZBOUV0UW5OUmlGTEVZODNhS3ZHL3RxTFdObkdsU05WeDdTTWNmb3ZrRkRxUWFtbSs4OHkxT3d3QUVZSzdxY29jZVg2WjdHR2NhWXVJZkdwYVgyTUNDRUxlUXZaKzhXeEVnT25JZno3R1l2c1lOakxaU2FSblY0RytJTFkxRjBRTlc2NFM5TnZqK0J3RGczaHQyQ3JOdnB3alZZbGo5VTNubXhFMFVHNW5lODNMTDVoaHFNcG0yNWttTDdlblZndzJrUXptVTJpZDRJS3UwQy9XYW9EUnVPMkY1ekU2M3ZKYnhOOEFZczczMzgrNEI0SEJiNkJaNk9VZ2c5NlExNVJBNDEvZ0lxeGFWUHh5VHBEZlRVNUdmU0x4b2NkWWVuaXFxcEZNdFpHMm45ZDB1N0dzUU5jRmtOY0czcURabTR0RG84dFpidXltMGEyVmNGMkU1aEZFZ1hCYStYTEpDZlhpLzc3T3FBRWpQMHg3UWRrM0I0M3A4S0cvQmFpb1A1UnNWOHpCR3ZIMXpBZ3lQaGEyck43MC90VDEzeXJtUGQ1UVlFZnd6ZXhqS3JWNG1XSXVSZzhOVEhZU1pKVWFleUN3VG9tODBWRlVKWEcrR1lUVXl2NVcyMmFCY25vUkdpQ2lLRVlUTE9rZ1hlY2RLRlRIbWNJQWVqUTlXZWxyMGExOTZLcTg3dzVLTk1Da2NDR0Zud0JORkxtZm5icE5xVDZyVUJ4eHMzWDVudFg5ZDhIVnRTWUlOVHNHWFhNWkNKN2ZuYldhamhnL2FveDBGdEhYMjFlRjZxSUdUOGoxeitsMm9wVStnZ3dVZ2toVVVnQ0gyVGZxQmorTUxNVlZ2cGdxSnNQS3Q1ODJjYUZLQXJJRkl2Tys5UXVweExuRUgyaHowNFRNVGZuVTZiUUM2ejFidVZlN2grdE9MbmgxWVBGc0xRODhhbmliLzdUVEM4azlEc0JUcTBBU2U4UjJHYlNFc21POXFiYk13Z0VhWVVoT0t0R2V5UXNTSmRoU2s2WHhYVGhyV0w5RW53QkNYRGtJQ01xZG50QXh5eU05bldzWjRiTDlKSHFFeGdXVW1mV0NoelBGQXFuM0Y0eTg5NlVxSFRaeGxxM1dHeXBuNUhIY2VtMkhxZjNJVnhLSDFpbmhxZFZ0a3J5RWlUV3JJN1pkamJxbnFSYmwrV2d0UHRLT093ZURsQ2FSczNSMnFYY2JOZ1ZobGVNazRJV25GOEQxNjk1QWVuVTFMd0hqT0pMa0NqeGdORmlXQUZFUEg5YUVYQU1QTEV4QT09IiwNCiAgIkF1dGhvcml6YXRpb24iOiAiQVdTNC1ITUFDLVNIQTI1NiBDcmVkZW50aWFsPVhYWFhYWFhYWFhYWFhYWFhYWFgvMjAyMDA0MDEvdXMtZWFzdC0xL2FwcHN5bmMvYXdzNF9yZXF1ZXN0LCBTaWduZWRIZWFkZXJzPWFjY2VwdDtjb250ZW50LWVuY29kaW5nO2NvbnRlbnQtdHlwZTtob3N0O3gtYW16LWRhdGU7eC1hbXotc2VjdXJpdHktdG9rZW4sIFNpZ25hdHVyZT04M0VYQU1QTEViY2MxZmUzZWU2OWY3NWNkNWViYmY0Y2I0ZjE1MGU0Zjk5Y2VjODY5ZjE0OWM1RVhBTVBMRWRjIg0KfQ"]
```

**표준 HTTP 헤더를 통한 헤더**

이 방법에서 호스트 및 기타 권한 부여 정보는 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 표준 HTTP 헤더를 사용하여 전송됩니다. 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

요청 헤더에 다음이 포함될 수 있습니다.

```
"sec-websocket-protocol" : ["graphql-ws"]
"accept": "application/json, text/javascript",
"content-encoding": "amz-1.0",
"content-type": "application/json; charset=UTF-8",
"host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
"x-amz-date": "20200401T001010Z",
"X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
"Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
```

사용자 지정 도메인을 사용하여 요청에 서명하려면 다음을 따르세요.

```
{
  url: "https://api.example.com/graphql/connect",
  data: "{}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

**예제**

```
{
  "accept": "application/json, text/javascript",
  "content-encoding": "amz-1.0",
  "content-type": "application/json; charset=UTF-8",
  "host": "api.example.com",
  "x-amz-date": "20200401T001010Z",
  "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
  "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
}
```

**쿼리 문자열이 있는 요청 URL**

```
wss://api.example.com/graphql?header=eyEXAMPLEHQiOiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFEXAMPLEQiLCJjb250ZW50LWVuY29kaW5nIjoEXAMPLEEuMCIsImNvbnRlbnQtdHlwZSI6ImFwcGxpY2F0aW9EXAMPLE47IGNoYXJzZXQ9VVRGLTgiLCJob3N0IjoiZXhhbXBsZEXAMPLENjc4OTAwMDAuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYEXAMPLEcy5jb20iLCJ4LWFtei1kYXRlIjoiMjAyMDA0MDFUMDAxMDEwWiIsIlgtEXAMPLElY3VyaXR5LVRva2VuIjoiQWdvSmIzSnBaMmx1WDJWakVBb2FEbUZ3TFhOdmRYUm9aV0Z6ZEMweUlrY3dSUUlnQWg5N0NsanE3d09QTDhLc3hQM1l0RHV5Yy85aEFqOFBoSjdGdmYzOFNnb0NJUURoSllKYkpsbmpQc3Bpb096dGorK3BFYWdXQ3ZlWlVqS0VuMHp5VWhCbXhpck5CUWpqLy8vLy8vLy8vLzhCRUFBYUREY3hPRGsyTkRneU56ZzFOU0lNbzFtV25wRVNXVW9ZdzRCa0txRUZTcm0zRFh1TDh3K1piVmM0SktqRFA0dlVDS05SNkxlOUM5cFpwOVBzVzBOb0Z5M3ZMQlVkQVh3dDZQSld1T1ZHOGZlWGZpRUVBKzFraGdGSy93RXR3Uis5ekY3TmFNTU1zZTA3d04yZ0cydEgwZUtNVFhuOEF3QVFYK3NNYnl0UW84aWVwUDlQWk96bFpzU0ZiL2RQNVE4aGs2WWpHVGFMMWVZY0tac1RrREFxMnVLRlE4bVlVVkE5RXRRbk5SaUZMRVk4M2FLdkcvdHFMV05uR2xTTlZ4N1NNY2ZvdmtGRHFRYW1tKzg4eTFPd3dBRVlLN3Fjb2NlWDZaN0dHY2FZdUlmR3BhWDJNQ0NFTGVRdlorOFd4RWdPbklmejdHWXZzWU5qTFpTYVJuVjRHK0lMWTFGMFFOVzY0UzlOdmorQndEZzNodDJDck52cHdqVllsajlVM25teEUwVUc1bmU4M0xMNWhocU1wbTI1a21MN2VuVmd3MmtRem1VMmlkNElLdTBDL1dhb0RSdU8yRjV6RTYzdkpieE44QVlzNzMzOCs0QjRIQmI2Qlo2T1VnZzk2UTE1UkE0MS9nSXF4YVZQeHlUcERmVFU1R2ZTTHhvY2RZZW5pcXFwRk10WkcybjlkMHU3R3NRTmNGa05jRzNxRFptNHREbzh0WmJ1eW0wYTJWY0YyRTVoRkVnWEJhK1hMSkNmWGkvNzdPcUFFalAweDdRZGszQjQzcDhLRy9CYWlvUDVSc1Y4ekJHdkgxekFneVBoYTJyTjcwL3RUMTN5cm1QZDVRWUVmd3pleGpLclY0bVdJdVJnOE5USFlTWkpVYWV5Q3dUb204MFZGVUpYRytHWVRVeXY1VzIyYUJjbm9SR2lDaUtFWVRMT2tnWGVjZEtGVEhtY0lBZWpROVdlbHIwYTE5NktxODd3NUtOTUNrY0NHRm53Qk5GTG1mbmJwTnFUNnJVQnh4czNYNW50WDlkOEhWdFNZSU5Uc0dYWE1aQ0o3Zm5iV2FqaGcvYW94MEZ0SFgyMWVGNnFJR1Q4ajF6K2wyb3BVK2dnd1Vna2hVVWdDSDJUZnFCaitNTE1WVnZwZ3FKc1BLdDU4MmNhRktBcklGSXZPKzlRdXB4TG5FSDJoejA0VE1UZm5VNmJRQzZ6MWJ1VmU3aCt0T0xuaDFZUEZzTFE4OGFuaWIvN1RUQzhrOURzQlRxMEFTZThSMkdiU0VzbU85cWJiTXdnRWFZVWhPS3RHZXlRc1NKZGhTazZYeFhUaHJXTDlFbndCQ1hEa0lDTXFkbnRBeHl5TTluV3NaNGJMOUpIcUV4Z1dVbWZXQ2h6UEZBcW4zRjR5ODk2VXFIVFp4bHEzV0d5cG41SEhjZW0ySHFmM0lWeEtIMWluaHFkVnRrcnlFaVRXckk3WmRqYnFucVJibCtXZ3RQdEtPT3dlRGxDYVJzM1IycVhjYk5nVmhsZU1rNElXbkY4RDE2OTVBZW5VMUx3SGpPSkxrQ2p4Z05GaVdBRkVQSDlhTklhcXMvWnhBPT0iLCJBdXRob3JpemF0aW9uIjoiQVdTNC1ITUFDLVNIQTI1NiBDcmVkZW50aWFsPVhYWFhYWFhYWFhYWFhYWFhYWFgvMjAxOTEwMDIvdXMtZWFzdC0xEXAMPLE5bmMvYXdzNF9yZXF1ZXN0LCBTaWduZWRIZWFkZXJzPWFjY2VwdDtjb250ZWEXAMPLE29kaW5nO2NvbnRlbnQtdHlwZTtob3EXAMPLEW16LWRhdGU7eC1hbXotc2VjdXJpdHktdG9rZW4sIFNpZ25hdHVyZT04MzE4EXAMPLEiY2MxZmUzZWU2OWY3NWNkEXAMPLE0Y2I0ZjE1MGU0Zjk5Y2VjODY5ZjE0OWM1ZDAzNDEXAMPLEn0=&payload=e30=
```

**참고**  
하나의 WebSocket 연결에는 여러 개의 구독이 있을 수 있습니다(각 구독이 서로 다른 인증 모드를 사용하더라도 상관없음). 이 연결을 구현하는 한 가지 방법은 첫 번째 구독에 대한 WebSocket 연결을 만든 후 마지막 구독이 등록 취소되면 이 연결을 닫는 것입니다. 마지막 구독이 등록 취소된 직후에 앱이 구독되는 경우 WebSocket 연결을 닫기 전에 몇 초 동안 대기하여 이 연결을 최적화할 수 있습니다. 모바일 앱 예제의 경우, 한 화면에서 다른 화면으로 변경할 때 *탑재 해제* 이벤트에서 구독을 중지하고 *탑재* 이벤트에서 다른 구독을 시작합니다.

### Lambda 권한 부여
<a name="lambda-auth"></a>

#### Lambda 권한 부여 헤더
<a name="lambda-auth-list"></a>

**헤더 콘텐츠**
+  `"Authorization": <string>`: `authorizationToken`으로 전달되는 값입니다.
+  `"host": <string>`: AWS AppSync GraphQL 엔드포인트의 호스트 또는 사용자 지정 도메인 이름입니다.

**예제**

```
{
    "Authorization":"M0UzQzM1MkQtMkI0Ni00OTZCLUI1NkQtMUM0MTQ0QjVBRTczCkI1REEzRTIxLTk5NzItNDJENi1BQjMwLTFCNjRFNzQ2NzlCNQo=",
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
}
```

**쿼리 문자열을 통한 헤더**

먼저 `host` 및 `Authorization`를 포함하는 JSON 객체가 문자열로 변환됩니다. 다음으로 이 문자열은 base64 인코딩을 사용하여 인코딩됩니다. 결과 base64 인코딩 문자열은 AWS AppSync 실시간 엔드포인트와의 연결을 설정`header`하기 위해 WebSocket URL에 라는 쿼리 파라미터로 추가됩니다. WebSocket 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

base64로 인코딩된 헤더 객체 외에도 빈 JSON 객체 \$1\$1도 base64로 인코딩되어 WebSocket URL에 `payload`로 명명된 별도의 쿼리 파라미터로 포함됩니다.

**`Sec-WebSocket-Protocol`을 통한 헤더**

`host` 및 `Authorization`를 포함하는 JSON 객체는 문자열로 변환된 다음 base64Url 인코딩을 사용하여 인코딩됩니다. 결과 base64Url-encoded 문자열에는 접두사 `header-`가 붙습니다. 그런 다음 접두사가 붙은이 문자열은 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 `Sec-WebSocket-Protocol` 헤더`graphql-ws`에 외에도 새 하위 프로토콜로 사용됩니다.

결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 헤더에는 다음 값이 포함됩니다.

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**표준 HTTP 헤더를 통한 헤더**

이 방법에서 호스트 및 권한 부여 정보는 AWS AppSync 실시간 엔드포인트와 WebSocket 연결을 설정할 때 표준 HTTP 헤더를 사용하여 전송됩니다. 결과 요청 URL은 다음과 같은 형식을 취합니다.

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

요청 헤더에 다음이 포함될 수 있습니다.

```
"sec-websocket-protocol" : ["graphql-ws"]
"Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
```

## 실시간 WebSocket 작업
<a name="real-time-websocket-operation"></a>

 AWS AppSync로 성공적인 WebSocket 핸드셰이크를 시작한 후 클라이언트는 후속 메시지를 전송하여 다양한 작업을 위해 AWS AppSync에 연결해야 합니다. 이러한 메시지에는 다음 데이터가 필요합니다.
+  `type`: 작업의 유형입니다.
+  `id`: 구독의 고유 식별자입니다. UUID를 이러한 목적으로 사용하는 것이 좋습니다.
+  `payload`: 작업 유형에 따라 연결된 페이로드입니다.

`type` 필드만 필수 필드이며, `id` 및 `payload` 필드는 선택 사항입니다.

### 이벤트 순서
<a name="sequence-of-events"></a>

구독 요청을 성공적으로 시작, 설정, 등록 및 처리하려면 클라이언트는 다음 순서를 따라야 단계를 완료해야 합니다.

1. 연결 초기화(`connection_init`)

1. 연결 승인(`connection_ack`)

1. 구독 등록(`start`)

1. 구독 승인(`start_ack`)

1. 구독 처리(`data`)

1. 구독 등록 취소(`stop`)

## 연결 초기화 메시지
<a name="connection-init-message"></a>

(선택 사항) 핸드셰이크가 성공하면 클라이언트는 `connection_init` 메시지를 전송하여 AWS AppSync 실시간 엔드포인트와 통신을 시작할 수 있습니다. 메시지는 JSON 객체를 다음과 같이 문자열로 변환하여 얻은 문자열입니다.

```
{ "type": "connection_init" }
```

## 연결 승인 메시지
<a name="connection-acknowledge-message"></a>

`connection_init` 메시지를 전송한 후 클라이언트는 `connection_ack` 메시지를 대기해야 합니다. `connection_ack`를 수신하기 전에 전송된 모든 메시지는 무시됩니다. 메시지는 다음과 같은 내용이어야 합니다.

```
{
  "type": "connection_ack",
  "payload": {
    // Time in milliseconds waiting for ka message before the client should terminate the WebSocket connection
    "connectionTimeoutMs": 300000
  }
}
```

## 연결 유지 메시지
<a name="keep-alive-message"></a>

클라이언트는 연결 승인 메시지 외에도 연결 유지 메시지를 주기적으로 수신합니다. 연결 제한 시간 내에 클라이언트가 연결 유지 메시지를 수신하지 않으면 클라이언트는 연결을 닫아야 합니다. AWS AppSync는 연결을 자동으로 종료할 때까지(24시간 후) 이러한 메시지를 계속 전송하고 등록된 구독을 처리합니다. 연결 유지 메시지는 하트비트이며 클라이언트가 승인할 필요가 없습니다.

```
{ "type": "ka" }
```

## 구독 등록 메시지
<a name="subscription-registration-message"></a>

클라이언트가 `connection_ack` 메시지를 수신한 후 클라이언트는 구독 등록 메시지를 AWS AppSync에 보낼 수 있습니다. 이 메시지 유형은 다음 필드가 포함된 문자열화된 JSON 객체입니다.
+  `"id": <string>`: 구독의 ID입니다. 이 ID는 각 구독에 고유해야 합니다. 그렇지 않으면 서버에서 구독 ID가 중복됨을 나타내는 오류를 반환합니다.
+  `"type": "start"`: 상수 `<string>` 파라미터입니다.
+  `"payload": <Object>`: 구독에 관련된 정보가 포함된 객체입니다.
  +  `"data": <string>`: GraphQL 쿼리 및 변수를 포함하는 문자열화된 JSON 객체입니다.
    +  `"query": <string>`: GraphQL 작업입니다.
    +  `"variables": <Object>`: 쿼리에 대한 변수가 포함된 객체입니다.
  +  `"extensions": <Object>`: 권한 부여 객체가 포함된 객체입니다.
+  `"authorization": <Object>`:권한 부여에 필요한 필드가 포함된 객체입니다.

### 구독 등록을 위한 권한 부여 개체
<a name="authorization-object-for-subscription-registration"></a>

[AWS AppSync API 권한 부여 모드를 기반으로 하는 헤더 파라미터 형식](#header-parameter-format-based-on-appsync-api-authorization-mode) 섹션의 동일한 규칙이 권한 부여 객체에도 적용됩니다. 유일한 예외는 IAM입니다. 이 경우 SigV4 서명 정보가 약간 다릅니다. 자세한 내용은 IAM 예제를 참조하십시오.

Amazon Cognito 사용자 풀 사용 예:

```
{
  "id": "ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
      "extensions": {
        "authorization": {
          "Authorization": "eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJEXAMPLEBieU5WNHhsQjhPVW9YMnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyJzdWIiOiJhNmNmMjcwNy0xNjgxLTQ1NDItEXAMPLENjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImU3YWVmMzEyLWUEXAMPLEY0Zi04YjlhLTRjMWY5M2Q5ZTQ2OCIsInRva2VuX3VzZSI6ImFjY2VzcyIsIEXAMPLEIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk2MTgzMzgsImlzcyI6Imh0dEXAMPLEXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zbEXAMPLEc3QtMl83OHY0SVZibVAiLCJleHAiOjE1NzAyNTQ3NTUsImlhdCI6MTU3MDI1MTE1NSwianRpIjoiMmIEXAMPLEktZTVkMi00ZDhkLWJiYjItNjA0YWI4MDEwOTg3IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1EXAMPLE0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3J6YWZlIn0.CT-qTCtrYeboUJ4luRSTPXaNewNeEXAMPLE14C6sfg05tO0fOMpiUwj9k19gtNCCMqoSsjtQoUweFnH4JYa5EXAMPLEVxOyQEQ4G7jQrt5Ks6STn53vuseR3zRW9snWgwz7t3ZmQU-RWvW7yQU3sNQRLEXAMPLEcd0yufBiCYs3dfQxTTdvR1B6Wz6CD78lfNeKqfzzUn2beMoup2h6EXAMPLE4ow8cUPUPvG0DzRtHNMbWskjPanu7OuoZ8iFO_Eot9kTtAlVKYoNbWkZhkD8dxutyoU4RSH5JoLAnrGF5c8iKgv0B2dfEXAMPLEIihxaZVJ9w9w48S4EXAMPLEcA",
          "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com"
         }
      }
  },
  "type": "start"
}
```

IAM 사용 예:

```
{
  "id": "eEXAMPLE-cf23-1234-5678-152EXAMPLE69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
    "extensions": {
      "authorization": {
        "accept": "application/json, text/javascript",
        "content-type": "application/json; charset=UTF-8",
        "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
        "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=b90131a61a7c4318e1c35ead5dbfdeb46339a7585bbdbeceeaff51f4022eb1fd",
        "content-encoding": "amz-1.0",
        "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
        "x-amz-date": "20200401T001010Z"
      }
    }
  },
  "type": "start"
}
```

사용자 지정 도메인 이름을 사용하는 예:

```
{
  "id": "key-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
      "extensions": {
        "authorization": {
          "x-api-key": "da2-12345678901234567890123456",
          "host": "api.example.com"
         }
      }
  },
  "type": "start"
}
```

SigV4 서명은 URL에 `/connect`를 추가할 필요가 없으며 JSON 문자열화된 GraphQL 작업은 `data`를 대체합니다. 다음은 SigV4 서명 요청의 예입니다.

```
{
  url: "https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql",
  data: "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

## 구독 승인 메시지
<a name="subscription-acknowledge-message"></a>

구독 시작 메시지를 전송한 후 클라이언트는 AWS AppSync가 `start_ack` 메시지를 전송할 때까지 기다려야 합니다. `start_ack` 메시지는 구독이 성공했음을 나타냅니다.

구독 승인 예:

```
{
  "type": "start_ack",
  "id": "eEXAMPLE-cf23-1234-5678-152EXAMPLE69"
}
```

## 오류 메시지
<a name="error-message"></a>

연결 초기화 또는 구독 등록이 실패하거나 서버에서 구독이 종료되는 경우 서버는 클라이언트에 오류 메시지를 전송합니다. 연결 시작 시간 중에 오류가 발생하면 서버에 의해 연결이 종료됩니다.
+  `"type": "error"`: 상수 `<string>` 파라미터입니다.
+  `"id": <string>`: 관련된 경우 해당 등록 구독의 ID입니다.
+  `"payload" <Object>`: 해당 오류 정보가 포함된 객체입니다.

예제:

```
{
  "type": "error",
  "payload": {
    "errors": [
      {
        "errorType": "LimitExceededError",
        "message": "Rate limit exceeded"
      }
    ]
  }
}
```

## 데이터 메시지 처리
<a name="processing-data-messages"></a>

클라이언트가 변형을 제출하면 AWS AppSync는 해당 변형에 관심이 있는 모든 구독자를 식별하고 구독 작업`id`의 해당 구독을 사용하여 각 `"start"` 구독자에게 `"type":"data"` 메시지를 보냅니다. 클라이언트는 데이터 메시지를 수신할 때 클라이언트가 해당 구독과 일치시킬 수 있도록 전송하는 구독 `id`를 추적해야 합니다.
+  `"type": "data"`: 상수 `<string>` 파라미터입니다.
+  `"id": <string>`: 해당 등록 구독의 ID입니다.
+  `"payload" <Object>`: 구독 정보가 포함된 객체입니다.

예제:

```
{
  "type": "data",
  "id": "ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": {
      "onCreateMessage": {
        "__typename": "Message",
        "message": "test"
      }
    }
  }
}
```

## 구독 등록 취소 메시지
<a name="subscription-unregistration-message"></a>

앱이 구독 이벤트 수신 대기를 중지하려는 경우 클라이언트는 다음과 같은 문자열화된 JSON 객체가 있는 메시지를 전송해야 합니다.
+  `"type": "stop"`: 상수 `<string>` 파라미터입니다.
+  `"id": <string>`: 등록 취소할 구독의 ID입니다.

예제:

```
{
  "type":"stop",
  "id":"ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69"
}
```

AWS AppSync는 다음과 같은 문자열화된 JSON 객체와 함께 확인 메시지를 다시 보냅니다.
+  `"type": "complete"`: 상수 `<string>` 파라미터입니다.
+  `"id": <string>`: 등록되지 않은 구독의 ID입니다.

클라이언트는 확인 메시지를 받은 후 이 특정 구독에 대한 메시지를 더 이상 받지 않습니다.

예제:

```
{
  "type":"complete",
  "id":"eEXAMPLE-cf23-1234-5678-152EXAMPLE69"
}
```

## WebSocket 연결 해제
<a name="disconnecting-the-websocket"></a>

연결을 해제하기 전에 클라이언트는 데이터 손실을 방지하기 위해 WebSocket 연결을 통해 현재 진행 중인 작업이 없는지 확인하는 데 필요한 논리를 갖춰야 합니다. WebSocket에서 연결 해제하기 전에 모든 구독을 등록 취소해야 합니다.

# APIs 병합 AWS AppSync
<a name="merged-api"></a>

조직 내에서 GraphQL의 사용이 확대됨에 따라 API 사용 편의성과 API 개발 속도 간의 상충 지점이 발생할 수 있습니다. 반면 조직은 애플리케이션 개발을 간소화하기 위해 AWS AppSync 및 GraphQL을 채택합니다. 이를 통해 개발자는 단일 네트워크 호출로 하나 이상의 데이터 도메인의 데이터에 안전하게 액세스, 조작 및 결합하는 데 사용할 수 있는 유연한 API를 사용할 수 있습니다. 반면 조직 내에서 단일 GraphQL API 엔드포인트로 결합된 다양한 데이터 도메인을 담당하는 팀은 서로 독립적으로 API 업데이트를 생성, 관리 및 배포하는 기능을 원할 수 있습니다. 이렇게 하면 개발 속도가 빨라집니다.

이러한 긴장을 해결하기 위해 AWS AppSync 병합된 APIs 기능을 사용하면 서로 다른 데이터 도메인의 팀이 독립적으로 AWS AppSync APIs(예: GraphQL 스키마, 해석기, 데이터 소스 및 함수)를 생성하고 배포한 다음 병합된 단일 API로 결합할 수 있습니다. 이를 통해 조직은 사용이 간편한 교차 도메인 API를 유지 관리하고 해당 API에 기여하는 여러 팀이 빠르고 독립적으로 API 업데이트를 수행할 수 있습니다.

다음 다이어그램은 병합된 API 워크플로를 보여줍니다.

![\[여러 소스 API가 단일 병합된 API 엔드포인트로 결합 APIs 되는 병합된 API 워크플로를 보여주는 다이어그램\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/merged-api-workflow.png)


조직은 병합된 APIs를 사용하여 여러 독립 소스 AWS AppSync APIs로 가져올 수 있습니다. AWS AppSync 이를 위해를 AWS AppSync 사용하면 AWS AppSync APIs 목록을 생성한 다음 스키마, 유형, 데이터 소스, 해석기 및 함수를 포함하여 소스 APIs와 연결된 모든 메타데이터를 새 AWS AppSync 병합된 API에 병합할 수 있습니다.

병합 중에 소스 API 데이터 콘텐츠의 불일치로 인해 병합 충돌이 발생할 수 있습니다(예: 여러 스키마 결합 시 형식 이름 충돌). 소스 API의 정의가 충돌하지 않는 간단한 사용 사례의 경우 소스 API 스키마를 수정할 필요가 없습니다. 결과 병합 API는 원본 AWS AppSync APIs. 충돌이 발생하는 복잡한 사용 사례의 경우 사용자/팀은 다양한 수단을 통해 충돌을 해결해야 합니다.는 사용자에게 병합 충돌을 줄일 수 있는 몇 가지 도구와 예제를 AWS AppSync 제공합니다.

에 구성된 후속 병합은 소스 APIs로 AWS AppSync 전파합니다.

## 병합된 API 및 페더레이션
<a name="merged-api-federation"></a>

GraphQL 커뮤니티에는 GraphQL 스키마를 결합하고 공유 그래프를 통해 팀 협업을 활성화하기 위한 많은 솔루션과 패턴이 있습니다. AWS AppSync 병합된 APIs 스키마 구성에 대한 *빌드 타임* 접근 방식을 채택합니다. 여기서 소스 APIs는 별도의 병합된 API로 결합됩니다. 또 다른 방법으로는 *런타임* 라우터를 여러 소스 API 또는 하위 그래프에 계층화하는 방식이 있습니다. 이 접근 방식에서 라우터는 요청을 수신하고, 메타데이터로 유지 관리하는 결합된 스키마를 참조하고, 요청 계획을 구성한 다음 기본 하위 그래프/서버에 요청 요소를 배포합니다. 다음 표에서는 AWS AppSync 병합된 API 빌드 타임 접근 방식을 GraphQL 스키마 구성에 대한 라우터 기반 런타임 접근 방식과 비교합니다.


|  |  |  | 
| --- |--- |--- |
| Feature | AppSync Merged API | Router-based solutions | 
| Sub-graphs managed independently | Yes | Yes | 
| Sub-graphs addressable independently | Yes | Yes | 
| Automated schema composition | Yes | Yes | 
| Automated conflict detection | Yes | Yes | 
| Conflict resolution via schema directives | Yes | Yes | 
| Supported sub-graph servers | AWS AppSync\$1 | Varies | 
| Network complexity | Single, merged API means no extra network hops. | Multi-layer architecture requires query planning and delegation, sub-query parsing and serialization/deserialization, and reference resolvers in sub-graphs to perform joins. | 
| Observability support | Built-in monitoring, logging, and tracing. A single, Merged API server means simplified debugging. | Build-your-own observability across router and all associated sub-graph servers. Complex debugging across distributed system. | 
| Authorization support | Built in support for multiple authorization modes. | Build-your-own authorization rules. | 
| Cross account security | Built-in support for cross-AWS cloud account associations. | Build-your-own security model. | 
| Subscriptions support | Yes | No | 

\$1 AWS AppSync 병합 APIs AWS AppSync 소스 APIs. AWS AppSync 및 비AWS AppSync 하위 그래프에서 스키마 구성을 지원해야 하는 경우 하나 이상의 AWS AppSync GraphQL 및/또는 병합된 APIs 라우터 기반 솔루션에 연결할 수 있습니다. 예를 들어 Apollo Federation v2: [Apollo GraphQL Federation AWS AppSync](https://aws.amazon.com/blogs/mobile/federation-appsync-subgraph/)과 함께 라우터 기반 아키텍처를 사용하여 AWS AppSync APIs로 추가하기 위한 참조 블로그를 참조하세요.

**Topics**
+ [병합된 API 및 페더레이션](#merged-api-federation)
+ [병합된 API 충돌 해결](#merged-api-conflict-resolution)
+ [스키마 구성](#configuring-schemas-merged-api)
+ [권한 부여 모드 구성](#configuring-authorization-merged-api)
+ [실행 역할 구성](#execution-roles-merged-api)
+ [APIs 사용하여 교차 계정 병합 API 구성 AWS RAM](#cross-account-merged-api)
+ [병합](#merges)
+ [병합된 API에 대한 추가 지원](#merge-api-additional-support)
+ [병합된 API 제한 사항](#merged-api-limits)
+ [병합된 API 고려 사항](#merged-api-considerations)
+ [병합된 API 생성](#creating-merged-api)

## 병합된 API 충돌 해결
<a name="merged-api-conflict-resolution"></a>

병합 충돌이 발생하는 경우는 사용자에게 문제(들)를 해결하는 데 도움이 되는 몇 가지 도구와 예제를 AWS AppSync 제공합니다.

### 병합된 API 스키마 지시문
<a name="merged-api-schema-directive"></a>

 AWS AppSync 에는 소스 API 간의 충돌을 줄이거나 해결하는 데 사용할 수 있는 몇 가지 GraphQL 명령이 도입되었습니다. APIs
+ *@canonical*: 이 지시문은 이름과 데이터가 비슷한 형식/필드의 우선 순위를 설정합니다. 둘 이상의 소스 API에 동일한 GraphQL 형식 또는 필드가 있는 경우 API 중 하나가 형식 또는 필드에 *canonical*로 주석을 달아 병합 중에 우선 순위가 지정되도록 할 수 있습니다. 다른 소스 API에서 이 지시문으로 주석을 달지 않은 충돌하는 형식/필드는 병합될 때 무시됩니다.
+ *@hidden*: 이 지시문은 특정 형식/필드를 캡슐화하여 병합 프로세스에서 제거합니다. 팀에서 내부 클라이언트만 특정 형식의 데이터에 액세스할 수 있도록 소스 API에서 특정 형식이나 작업을 제거하거나 숨기고 싶을 수 있습니다. 이 지시문이 연결되면 형식이나 필드가 병합된 API에 병합되지 않습니다.
+ *@renamed*: 이 지시문은 형식/필드의 이름을 변경하여 이름 충돌을 줄입니다. 서로 다른 API에 동일한 형식 또는 필드 이름이 사용되는 경우가 있습니다. 그러나 이들 모두 병합된 스키마에서 사용할 수 있어야 합니다. 모든 항목을 병합된 API에 포함하는 간단한 방법은 필드 이름을 비슷하지만 다른 이름으로 바꾸는 것입니다.

제공되는 유틸리티 스키마 지시문을 표시하려면 다음 예를 고려해 보세요.

이 예에서는 두 개의 소스 API를 병합한다고 가정합니다. 게시물(예: 댓글 섹션 또는 소셜 미디어 게시물)을 생성하고 검색하는 두 개의 스키마가 제공됩니다. 형식과 필드가 매우 유사하다고 가정하면 병합 작업 중에 충돌이 발생할 가능성이 높습니다. 아래 스니펫은 각 스키마의 형식과 필드를 보여 줍니다.

*Source1.graphql*이라는 첫 번째 파일은 사용자가 `putPost` 변형을 사용하여 `Posts`를 생성할 수 있게 하는 GraphQL 스키마입니다. 각 `Post`에는 제목과 ID가 포함되어 있습니다. ID는 `User` 또는 게시자의 정보(이메일 및 주소)와 `Message` 또는 페이로드(콘텐츠)를 참조하는 데 사용됩니다. `User` 형식에는 *@canonical* 태그로 주석이 달립니다.

```
# This snippet represents a file called Source1.graphql

type Mutation {
    putPost(id: ID!, title: String!): Post
}

type Post {
    id: ID!
    title: String!
}

type Message {
   id: ID!
   content: String
}

type User @canonical {
   id: ID!
   email: String!
   address: String!
}

type Query {
    singlePost(id: ID!): Post
    getMessage(id: ID!): Message
}
```

*Source2.graphql*이라는 두 번째 파일은 *Source1.graphql*과 매우 유사한 작업을 수행하는 GraphQL 스키마입니다. 하지만 각 형식의 필드는 서로 다르다는 점에 유의하세요. 이 두 스키마를 병합하면 이러한 차이로 인해 병합 충돌이 발생합니다.

또한 *Source2.graphql*에는 이러한 충돌을 줄이기 위한 몇 가지 지시문이 포함되어 있다는 점도 참고하세요. `Post` 형식에는 병합 작업 중에 자체적으로 난독화할 수 있도록 *@hidden* 태그가 주석으로 달려 있습니다. `Message` 형식에는 다른 `Message` 형식과 이름이 충돌하는 경우 형식 이름을 `ChatMessage`로 수정할 수 있도록 *@renamed* 태그가 주석으로 달려 있습니다.

```
# This snippet represents a file called Source2.graphql

type Post @hidden  {
    id: ID!
    title: String!
    internalSecret: String!
}

type Message @renamed(to: "ChatMessage") {
   id: ID!
   chatId: ID!
   from: User!
   to: User!
}

# Stub user so that we can link the canonical definition from Source1
type User {
   id: ID!
}

type Query {
    getPost(id: ID!): Post
    getMessage(id: ID!): Message @renamed(to: "getChatMessage")
}
```

병합이 발생하면 다음과 같이 `MergedSchema.graphql` 파일이 생성됩니다.

```
# This snippet represents a file called MergedSchema.graphql

type Mutation {
    putPost(id: ID!, title: String!): Post
}

# Post from Source2 was hidden so only uses the Source1 definition. 
type Post {
    id: ID!
    title: String!
}

# Renamed from Message to resolve the conflict
type ChatMessage {
   id: ID!
   chatId: ID!
   from: User!
   to: User!
}

type Message {
   id: ID!
   content: String
}

# Canonical definition from Source1
type User {
   id: ID!
   email: String!
   address: String!
}

type Query {
    singlePost(id: ID!): Post
    getMessage(id: ID!): Message
    
    # Renamed from getMessage
    getChatMessage(id: ID!): ChatMessage
}
```

병합에서 몇 가지 사항이 발생했습니다.
+ *@canonical* 주석으로 인해 *Source1.graphql*의 `User` 형식이 *Source2.graphql*의 `User` 형식보다 우선 순위로 지정되었습니다.
+ *Source1.graphql*의 `Message` 형식이 병합에 포함되었습니다. 하지만 *Source2.graphql*의 `Message`에 이름 충돌이 발생했습니다. *@renamed* 주석으로 인해 병합에 함께 포함되었지만 대체 이름인 `ChatMessage`가 사용되었습니다.
+ *Source1.graphql*의 `Post` 형식은 포함되었지만, *Source2.graphql*의 `Post` 형식은 포함되지 않았습니다. 일반적으로는 이 형식에서 충돌이 발생하지만 *Source2.graphql*의 `Post` 형식에 *@hidden* 주석이 있으므로 해당 데이터가 난독화되어 병합에 포함되지 않았습니다. 그 결과 충돌은 발생하지 않았습니다.
+ 두 파일의 내용을 모두 포함하도록 `Query` 형식이 업데이트되었습니다. 그러나 지시문으로 인해 `GetMessage` 쿼리 하나의 이름이 `GetChatMessage`로 변경되었습니다. 이를 통해 이름이 같은 두 쿼리 간의 이름 충돌이 해결되었습니다.

충돌하는 유형에 지시문이 추가되지 않는 경우도 있습니다. 여기서, 병합된 형식에는 해당 형식의 모든 소스 정의에 있는 모든 필드의 조합이 포함됩니다. 예를 들어 다음 예제를 고려해 보십시오.

*Source1.graphql*이라는 이 스키마를 사용하면 `Posts`를 생성하고 검색할 수 있습니다. 구성은 이전 예제와 비슷하지만 정보가 더 적습니다.

```
# This snippet represents a file called Source1.graphql

type Mutation {
    putPost(id: ID!, title: String!): Post
}

type Post  {
    id: ID!
    title: String!
}

type Query {
    getPost(id: ID!): Post
}
```

*Source2.graphql*이라는 이 스키마를 사용하면 `Reviews`(예: 영화 평점 또는 음식점 리뷰)를 생성하고 검색할 수 있습니다. `Reviews`는 ID 값이 동일한 `Post`와 연결됩니다. 여기에는 전체 리뷰 게시물의 제목, 게시물 ID, 페이로드 메시지가 모두 포함됩니다.

병합하면 두 `Post` 형식 간에 충돌이 발생합니다. 이 문제를 해결할 주석이 없으므로 기본 동작은 충돌하는 형식에 대해 조합 작업을 수행하는 것입니다.

```
# This snippet represents a file called Source2.graphql

type Mutation {
    putReview(id: ID!, postId: ID!, comment: String!): Review
}

type Post  {
    id: ID!
    reviews: [Review]
}

type Review {
   id: ID!
   postId: ID!
   comment: String!
}

type Query {
    getReview(id: ID!): Review
}
```

병합이 발생하면 다음과 같이 `MergedSchema.graphql` 파일이 생성됩니다.

```
# This snippet represents a file called MergedSchema.graphql

type Mutation {
    putReview(id: ID!, postId: ID!, comment: String!): Review
    putPost(id: ID!, title: String!): Post
}

type Post  {
    id: ID!
    title: String!
    reviews: [Review]
}

type Review {
   id: ID!
   postId: ID!
   comment: String!
}

type Query {
    getPost(id: ID!): Post
    getReview(id: ID!): Review
}
```

병합에서 몇 가지 사항이 발생했습니다.
+ `Mutation` 형식은 충돌이 없었고 병합되었습니다.
+ `Post` 형식 필드는 조합 작업을 통해 결합되었습니다. 이 둘의 조합으로 어떻게 단일 `id`, `title` 및 단일 `reviews`가 생성했는지를 주목해 보세요.
+ `Review` 형식은 충돌이 없었고 병합되었습니다.
+ `Query` 형식은 충돌이 없었고 병합되었습니다.

### 공유 형식의 해석기 관리
<a name="resolvers-shared-types-merged-api"></a>

위 예제에서 *Source1.graphql*이 `PostDatasource`라는 DynamoDB 데이터 원본을 사용하는 `Query.getPost`에 유닛 해석기를 구성한 경우를 고려해 보세요. 이 해석기는 `Post` 형식의 `id` 및 `title`을 반환합니다. 이제 *Source2.graphql*에서 두 함수를 실행하는 `Post.reviews`에 파이프라인 해석기를 구성했다고 가정해 보겠습니다. `Function1`에는 사용자 지정 권한 부여 검사를 수행할 수 있는 `None` 데이터 소스가 연결되어 있습니다. `Function2`에는 `reviews` 테이블을 쿼리하기 위해 DynamoDB 데이터 소스가 연결되어 있습니다.

```
query GetPostQuery {
    getPost(id: "1") {
        id,
        title,
        reviews
    }
}
```

클라이언트가 위의 쿼리를 병합된 API 엔드포인트로 실행하면 AWS AppSync 서비스는 먼저 `Query.getPost`에서에 대한 단위 해석기를 실행`Source1`하여를 호출`PostDatasource`하고 DynamoDB에서 데이터를 반환합니다. 그런 다음 `Function1`이 사용자 지정 권한 부여 로직을 수행하고 `Function2`가 `$context.source`에서 발견된 `id`에 제공된 리뷰를 반환하는 `Post.reviews` 파이프라인 해석기를 실행합니다. 서비스는 요청을 단일 GraphQL 실행으로 처리하며 이 단순한 요청에는 단일 요청 토큰만 필요합니다.

### 공유 형식의 해석기 충돌 관리
<a name="resolver-conflict-shared-type-merged-api"></a>

`Source2`의 필드 해석기 외에도 한 번에 여러 필드를 제공하기 위해 `Query.getPost`에 해석기도 구현하는 다음과 같은 경우를 생각해 보세요. *Source1.graphql*은 다음과 같을 수 있습니다.

```
# This snippet represents a file called Source1.graphql

type Post  {
    id: ID!
    title: String!
    date: AWSDateTime!
}

type Query {
    getPost(id: ID!): Post
}
```

*Source2.graphql*은 다음과 같을 수 있습니다.

```
# This snippet represents a file called Source2.graphql

type Post  {
  id: ID!
  content: String!
  contentHash: String! 
  author: String! 
}

type Query {
    getPost(id: ID!): Post
}
```

병합 AWS AppSync 된 APIs는 여러 소스 해석기를 동일한 필드에 연결할 수 없으므로이 두 스키마를 병합하려고 하면 병합 오류가 발생합니다. 이 충돌을 해결하려면 *Source2.graphql*이 `Post` 형식에서 소유한 필드를 정의하는 별도의 형식을 추가해야 하는 필드 해석기 패턴을 구현할 수 있습니다. 다음 예제에서는 `PostInfo`라는 형식을 추가하는데, 여기에는 *Source2.graphql*에서 해석할 내용 및 작성자 필드가 포함되어 있습니다. *Source1.graphql*은 `Query.getPost`에 연결된 해석기를 구현하고, *Source2.graphql*은 이제 `Post.postInfo`에 해석기를 연결하여 모든 데이터가 성공적으로 검색될 수 있도록 합니다.

```
type Post  {
  id: ID!
  postInfo: PostInfo
}

type PostInfo {
   content: String!
   contentHash: String!
   author: String!
}

type Query {
    getPost(id: ID!): Post
}
```

이러한 충돌을 해결하려면 소스 API 스키마를 다시 작성하고 잠재적으로 클라이언트도 쿼리를 변경해야 하지만, 이 접근 방식의 장점은 병합된 해석기의 소유권이 소스 팀 간에 명확하게 유지된다는 것입니다.

## 스키마 구성
<a name="configuring-schemas-merged-api"></a>

두 당사자는 병합된 API를 생성하기 위한 스키마 구성을 담당합니다.
+ **병합된 API 소유자** - 병합된 API 소유자는 병합된 API의 권한 부여 로직과 고급 설정(예: 로깅, 추적, 캐싱, WAF 지원)을 구성해야 합니다.
+ **관련 소스 API 소유자** - 관련 API 소유자는 병합된 API를 구성하는 스키마, 해석기, 데이터 원본을 구성해야 합니다.

병합된 API의 스키마는 관련 소스 API의 스키마에서 생성되므로 **읽기 전용**입니다. 즉, 스키마 변경은 소스 API에서 시작해야 합니다. AWS AppSync 콘솔에서 스키마 창 위의 드롭다운 목록을 사용하여 병합된 스키**마**와 병합된 APIs에 포함된 소스 API의 개별 스키마 간에 전환할 수 있습니다.

## 권한 부여 모드 구성
<a name="configuring-authorization-merged-api"></a>

여러 권한 부여 모드를 사용하여 병합된 API를 보호할 수 있습니다. 의 권한 부여 모드에 대한 자세한 내용은 [권한 부여 및 인증을](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html) AWS AppSync참조하세요.

병합된 API와 함께 사용할 수 있는 권한 부여 모드는 다음과 같습니다.
+  **API 키**: 가장 간단한 권한 부여 전략입니다. 모든 요청에는 `x-api-key` 요청 헤더 아래에 API 키가 포함되어야 합니다. 만료된 API 키는 만료일 이후 60일 동안 보관됩니다.
+  **AWS Identity and Access Management(IAM)**: AWS IAM 권한 부여 전략은 **sigv4에 서명된** 모든 요청을 승인합니다.
+  **Amazon Cognito 사용자 풀**: Amazon Cognito 사용자 풀을 통해 사용자에게 권한을 부여하여 보다 세밀하게 제어할 수 있도록 합니다.
+  **AWS Lambda 권한 부여자**: 사용자 지정 로직을 사용하여 AWS AppSync API에 대한 액세스를 인증하고 권한을 부여할 수 있는 서버리스 함수입니다.
+ **OpenID Connect**: 이 권한 부여 유형은 OIDC 호환 서비스에서 제공하는 OpenID Connect(OIDC) 토큰을 강제로 적용합니다. 애플리케이션에서는 OIDC 공급자가 액세스 제어를 위해 정의한 사용자 및 권한을 활용합니다.

병합된 API의 권한 부여 모드는 병합된 API 소유자가 구성합니다. 병합 작업 시 병합된 API는 소스 API에 구성된 기본 권한 부여 모드를 자체 기본 권한 부여 모드 또는 보조 권한 부여 모드로 포함해야 합니다. 그렇지 않으면 호환되지 않고 충돌이 발생하여 병합 작업이 실패합니다. 소스 API에서 다중 인증 지시문을 사용하는 경우 병합 프로세스에서 이러한 지시문을 통합 엔드포인트에 자동으로 병합할 수 있습니다. 소스 API의 기본 권한 부여 모드가 병합된 API의 기본 권한 부여 모드와 일치하지 않는 경우 소스 API의 형식에 대한 권한 부여 모드가 일관되도록 하기 위해 이러한 인증 지시문을 자동으로 추가합니다.

## 실행 역할 구성
<a name="execution-roles-merged-api"></a>

병합된 API를 생성할 때는 서비스 역할을 정의해야 합니다. AWS 서비스 역할은 AWS 서비스가 사용자를 대신하여 작업을 수행하는 데 사용하는 AWS Identity and Access Management(IAM) 역할입니다.

이러한 맥락에서 병합된 API는 소스 API에 구성된 데이터 원본의 데이터에 액세스하는 해석기를 실행해야 합니다. 이를 위한 필수 서비스 역할은 `mergedApiExecutionRole`이며, `appsync:SourceGraphQL` IAM 권한을 통해 병합된 API에 포함된 소스 API에서 요청을 실행할 수 있는 명시적 액세스 권한이 있어야 합니다. GraphQL 요청을 실행하는 동안 AWS AppSync 서비스는이 서비스 역할을 수임하고 해당 역할에 `appsync:SourceGraphQL` 작업을 수행할 수 있는 권한을 부여합니다.

AWS AppSync 는 IAM API에서 IAM 권한 부여 모드가 작동하는 방식과 같은 요청 내의 특정 최상위 필드에 대해이 권한을 허용하거나 거부할 APIs 지원합니다. non-top-level 필드의 경우 소스 API ARN 자체에 대한 권한을 정의해야 AWS AppSync 합니다. 병합된 API의 최상위 수준이 아닌 특정 필드에 대한 액세스를 제한하려면 Lambda 내에서 사용자 지정 로직을 구현하거나 *@hidden* 지시문을 사용하여 병합된 API에서 소스 API 필드를 숨기는 것이 좋습니다. 역할이 소스 API 내에서 모든 데이터 작업을 수행하도록 허용하려면 아래 정책을 추가할 수 있습니다. 첫 번째 리소스 항목은 모든 최상위 필드에 대한 액세스를 허용하고 두 번째 항목은 소스 API 리소스 자체에서 권한을 부여하는 하위 해석기를 포함합니다.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [{
        "Effect": "Allow", 
        "Action": [ "appsync:SourceGraphQL"], 
        "Resource": [ 
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/*", 
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId"] 
    }] 
}
```

------

특정 최상위 필드로만 액세스를 제한하려면 다음과 같은 정책을 사용할 수 있습니다.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [{
        "Effect": "Allow", 
        "Action": [ "appsync:SourceGraphQL"], 
        "Resource": [ 
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/types/Query/fields/<Field-1>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId"] 
    }] 
}
```

------

콘솔 AWS AppSync API 생성 마법사를 사용하여 서비스 역할을 생성하여 병합된 API가 병합된 API와 동일한 계정에 있는 소스 APIs에 구성된 리소스에 액세스할 수 있도록 할 수도 있습니다. 소스 APIs가 병합된 API와 동일한 계정에 있지 않은 경우 먼저 AWS Resource Access Manager()를 사용하여 리소스를 공유해야 합니다AWS RAM.

## APIs 사용하여 교차 계정 병합 API 구성 AWS RAM
<a name="cross-account-merged-api"></a>

병합된 API를 생성할 때 AWS Resource Access Manager()를 통해 공유된 다른 계정의 소스 APIs를 선택적으로 연결할 수 있습니다AWS RAM. AWS RAM 를 사용하면 AWS 계정 간, 조직 또는 조직 단위(OUs) 내, IAM 역할 및 사용자와 리소스를 안전하게 공유할 수 있습니다.

AWS AppSync 는 단일 병합 APIs에서 여러 계정의 소스 API 구성 및 액세스를 지원하기 AWS RAM 위해와 통합됩니다.를 AWS RAM 사용하면 리소스 공유 또는 리소스 컨테이너와 각 리소스에 대해 공유될 권한 세트를 생성할 수 있습니다. 리소스 공유에 AWS AppSync APIs를 추가할 수 있습니다 AWS RAM. 리소스 공유 내에서 AWS AppSync 는 RAM의 AWS AppSync API와 연결할 수 있는 세 가지 권한 세트를 제공합니다.

1. `AWSRAMPermissionAppSyncSourceApiOperationAccess`: 다른 권한이 지정되지 않은 AWS RAM 경우에서 AWS AppSync API를 공유할 때 추가되는 기본 권한 세트입니다. 이 권한 세트는 소스 AWS AppSync API를 병합된 API 소유자와 공유하는 데 사용됩니다. 이 권한 집합에는 소스 API의 `appsync:AssociateMergedGraphqlApi`에 대한 권한과 런타임 시 소스 API 리소스에 액세스하는 데 필요한 `appsync:SourceGraphQL` 권한이 포함됩니다.

1. `AWSRAMPermissionAppSyncMergedApiOperationAccess`: 이 권한 집합은 소스 API 소유자와 병합된 API를 공유할 때 구성해야 합니다. 이 권한 집합은 대상 보안 주체가 소유한 모든 소스 API를 병합된 API에 연결하고 병합된 API의 소스 API 연결을 읽고 업데이트하는 기능을 포함하여 병합된 API를 구성할 수 있는 기능을 소스 API에 제공합니다.

1. `AWSRAMPermissionAppSyncAllowSourceGraphQLAccess`:이 권한 세트를 사용하면 AWS AppSync API와 함께 `appsync:SourceGraphQL` 권한을 사용할 수 있습니다. 병합된 API 소유자와 소스 API를 공유하는 데 사용되도록 의도된 권한 집합입니다. 소스 API 작업 액세스를 위한 기본 권한 집합과 달리 이 권한 집합에는 런타임 권한 `appsync:SourceGraphQL`만 포함됩니다. 사용자가 병합된 API 작업 액세스를 소스 API 소유자와 공유하기로 선택한 경우, 병합된 API 엔드포인트를 통해 런타임 액세스 권한을 가지려면 소스 API의 이 권한을 병합된 API 소유자에게 공유해야 합니다.

AWS AppSync 는 고객 관리형 권한도 지원합니다. 제공된 AWS관리형 권한 중 하나가 작동하지 않는 경우 자체 고객 관리형 권한을 생성할 수 있습니다. 고객 관리형 권한은를 사용하여 리소스를 공유하는 조건에서 수행할 수 있는 작업을 정확하게 지정하여 작성하고 유지 관리하는 관리형 권한입니다 AWS RAM.를 AWS AppSync 사용하면 자체 권한을 생성할 때 다음 작업 중에서 선택할 수 있습니다.

1. `appsync:AssociateSourceGraphqlApi`

1. `appsync:AssociateMergedGraphqlApi`

1. `appsync:GetSourceApiAssociation`

1. `appsync:UpdateSourceApiAssociation`

1. `appsync:StartSchemaMerge`

1. `appsync:ListTypesByAssociation`

1. `appsync:SourceGraphQL`

에서 소스 API 또는 병합된 API를 올바르게 공유하고 필요한 AWS RAM 경우 리소스 공유 초대가 수락되면 병합된 API에서 소스 API 연결을 생성하거나 업데이트할 때 AWS AppSync 콘솔에 표시됩니다. 에서 제공하는 `ListGraphqlApis` 작업을 호출 AWS AppSync 하고 `OTHER_ACCOUNTS` 소유자 필터를 사용하여 권한 세트 AWS RAM 와 관계없이를 사용하여 공유된 모든 AWS AppSync APIs를 나열할 수도 있습니다.

**참고**  
 AWS RAM 를 통해 공유 AWS RAM 하려면의 호출자가 공유 중인 모든 API에서 `appsync:PutResourcePolicy` 작업을 수행할 수 있는 권한을 가져야 합니다.

## 병합
<a name="merges"></a>

### 병합 관리
<a name="managing-merges"></a>

병합된 APIs는 통합 AWS AppSync 엔드포인트에서 팀 협업을 지원하기 위한 것입니다. 팀은 백엔드에서 격리된 자체 소스 GraphQL API를 독립적으로 발전시킬 수 있으며, AWS AppSync 서비스는 단일 병합 API 엔드포인트로의 리소스 통합을 관리하여 협업의 어려움을 줄이고 개발 리드 타임을 줄일 수 있습니다.

### 자동 병합
<a name="auto-merge"></a>

 AWS AppSync 병합된 APIs와 연결된 소스 API는 소스 API를 변경한 후 병합된 API에 자동으로 병합(자동 병합)되도록 구성할 수 있습니다. 이렇게 하면 소스 API의 변경 사항이 백그라운드에서 병합된 API 엔드포인트로 항상 전달됩니다. 소스 API 스키마의 모든 변경 사항은 병합된 API의 기존 정의와 병합 충돌을 일으키지 않는 한 병합된 API에서 업데이트됩니다. 소스 API의 업데이트가 해석기, 데이터 원본 또는 함수를 업데이트하는 경우 가져온 리소스도 업데이트됩니다. 자동으로 해결(자동 해결)할 수 없는 새로운 충돌이 발생하면 병합 작업 중에 지원되지 않는 충돌로 인해 병합된 API 스키마 업데이트가 거부됩니다. 콘솔에서 상태가 `MERGE_FAILED`인 각 소스 API 연결에 대한 오류 메시지를 확인할 수 있습니다. AWS SDK를 사용하거나 다음과 같이 AWS CLI를 사용하여 지정된 소스 API 연결에 대한 `GetSourceApiAssociation` 작업을 호출하여 오류 메시지를 검사할 수도 있습니다.

```
aws appsync get-source-api-association --merged-api-identifier <Merged API ARN> --association-id <SourceApiAssociation id>
```

그러면 다음 형식의 결과가 생성됩니다.

```
{
    "sourceApiAssociation": {
        "associationId": "<association id>",
        "associationArn": "<association arn>",
        "sourceApiId": "<source api id>",
        "sourceApiArn": "<source api arn>",
        "mergedApiArn": "<merged api arn>",
        "mergedApiId": "<merged api id>",
        "sourceApiAssociationConfig": {
            "mergeType": "MANUAL_MERGE"
        },
        "sourceApiAssociationStatus": "MERGE_FAILED",
        "sourceApiAssociationStatusDetail": "Unable to resolve conflict on object with name title: Merging is not supported for fields with different types."
    }
}
```

### 수동 병합
<a name="manual-merges"></a>

소스 API의 기본 설정은 수동 병합입니다. 병합된 APIs가 마지막으로 업데이트된 이후 소스 API에서 발생한 변경 사항을 병합하기 위해 소스 API 소유자는 AWS AppSync 콘솔에서 또는 AWS SDK 및 AWS CLI에서 사용할 수 있는 `StartSchemaMerge` 작업을 통해 수동 병합을 호출할 수 있습니다.

## 병합된 API에 대한 추가 지원
<a name="merge-api-additional-support"></a>

### 구독 구성
<a name="config-subscription"></a>

GraphQL 스키마 구성에 대한 라우터 기반 접근 방식과 달리 AWS AppSync 병합된 APIs GraphQL 구독에 대한 기본 지원을 제공합니다. 관련 소스 API에 정의된 모든 구독 작업은 수정 없이 병합된 API에 자동으로 병합되어 작동합니다. 가 서버리스 WebSockets 연결을 통해 구독을 AWS AppSync 지원하는 방법에 대한 자세한 내용은 [실시간 데이터를](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html) 참조하세요.

### 관측성 구성
<a name="config-observability"></a>

AWS AppSync 병합된 APIs [Amazon CloudWatch](https://docs.aws.amazon.com/appsync/latest/devguide/monitoring.html)를 통해 기본 제공 로깅, 모니터링 및 지표를 제공합니다. AWS AppSync 또한를 통한 추적에 대한 기본 제공 지원을 제공합니다[AWS X-Ray](https://docs.aws.amazon.com/appsync/latest/devguide/x-ray-tracing.html).

### 사용자 지정 도메인 구성
<a name="config-custom-domain"></a>

AWS AppSync 병합된 APIs 병합된 API의 [GraphQL 및 실시간 엔드포인트](https://docs.aws.amazon.com/appsync/latest/devguide/custom-domain-name.html)와 함께 사용자 지정 도메인을 사용할 수 있는 기본 지원을 제공합니다.

### 캐싱 구성
<a name="config-caching"></a>

AWS AppSync 병합된 APIs 선택적으로 요청 수준 및/또는 해석기 수준 응답을 캐싱하고 응답 압축을 위한 기본 지원을 제공합니다. 자세히 알아보려면 [캐싱 및 압축](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)을 참조하세요.

### 프라이빗 API 구성
<a name="config-private-api"></a>

AWS AppSync 병합된 APIs 병합된 APIs의 GraphQL 및 실시간 엔드포인트에 대한 액세스를 [구성할 수 있는 VPC 엔드포인트](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html)에서 발생하는 트래픽으로 제한하는 프라이빗 API에 대한 기본 지원을 제공합니다.

### 방화벽 규칙 구성
<a name="config-firewall"></a>

AWS AppSync 병합된 APIs에 대한 기본 지원을 제공하므로 [웹 애플리케이션 방화벽 규칙을](https://docs.aws.amazon.com/appsync/latest/devguide/WAF-Integration.html) 정의하여 APIs 보호할 AWS WAF수 있습니다.

### 감사 로그 구성
<a name="config-audit"></a>

AWS AppSync 병합된 APIs AWS CloudTrail에 대한 기본 지원을 제공하므로 [감사 로그를 구성하고 관리할](https://docs.aws.amazon.com/appsync/latest/devguide/cloudtrail-logging.html) 수 있습니다.

## 병합된 API 제한 사항
<a name="merged-api-limits"></a>

병합된 API를 개발하기 전에 다음 규칙을 고려해야 합니다.

1. 병합된 API는 다른 병합된 API의 소스 API가 될 수 없습니다.

1. 소스 API는 둘 이상의 병합된 API와 연결할 수 없습니다.

1. 병합된 API 스키마 문서의 기본 크기 제한은 10MB입니다.

1. 병합된 API와 연결할 수 있는 소스 API의 수는 기본적으로 10개입니다. 그러나 병합된 API에서 10개 이상의 소스 API가 필요하다면 제한 증가를 요청할 수 있습니다.

## 병합된 API 고려 사항
<a name="merged-api-considerations"></a>

병합된 APIs

여러 소스 APIs 단일 엔드포인트로 병합하면 GraphQL 스키마 및 쿼리의 크기와 복잡성이 증가할 수 있습니다. 병합된 스키마가 증가함에 따라 쿼리는 단일 요청을 이행하기 위해 여러 해석기를 통과해야 할 수 있으며, 이로 인해 전체 요청 시간에 지연 시간이 추가될 수 있습니다. 예를 들어 여러 소스 APIs의 필드에 액세스하는 쿼리는 각 소스 API에서 해석기를 순서대로 실행해야 AWS AppSync 할 수 있으며, 각 해석기는 총 응답 시간에 추가됩니다.

개발 중에 그리고 실제 로드 조건에서 병합된 APIs를 철저하게 테스트하여 비즈니스 요구 사항을 충족하는지 확인하는 것이 좋습니다. 다음에 특히 주의하십시오.
+ 병합된 스키마의 깊이와 복잡성, 특히 여러 소스 APIs.
+ 공통 쿼리 패턴을 충족하기 위해 실행해야 하는 해석기 수입니다.
+ 예상 로드 시 데이터 소스 및 해석기의 성능 특성입니다.
+ 여러 소스 APIs.

캐싱, 데이터 소스 요청 일괄 처리, 소스 API 스키마 설계와 같은 성능 최적화를 구현하여 일반적인 작업에 필요한 해석기 실행 수를 최소화하는 것이 좋습니다.

## 병합된 API 생성
<a name="creating-merged-api"></a>

**콘솔에서 병합된 API를 만드는 방법**

1. 에 로그인 AWS Management Console 하고 [AWS AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **대시보드**에서 **API 생성**을 선택합니다.

1. **병합된 API**를 선택한 후 **다음**을 선택합니다.

1. **API 세부 정보 지정** 페이지에서 다음 정보를 입력합니다.

   1. **API 세부 정보**에서 다음 정보를 입력합니다.

      1. 병합된 API의 **API 이름**을 지정합니다. 이 필드에서 GraphQL API에 레이블을 지정하여 다른 GraphQL API와 쉽게 구분할 수 있습니다.

      1. **연락처 세부 정보**를 지정합니다. 이 필드는 선택 사항이며 GraphQL API에 이름 또는 그룹을 연결합니다. 이 필드는 다른 리소스에 연결되거나 다른 리소스에 의해 생성되지 않으며 API 이름 필드와 매우 유사하게 작동합니다.

   1. **서비스 역할**에서가 런타임에 리소스를 안전하게 가져오고 사용할 AWS AppSync 수 있도록 병합된 API에 IAM 실행 역할을 연결해야 합니다. **새 서비스 역할 생성 및 사용을** 선택할 수 있습니다. 그러면에서 사용할 정책 및 리소스를 지정할 AWS AppSync 수 있습니다. **기존 서비스 역할 사용**을 선택한 다음 드롭다운 목록에서 역할을 선택하여 기존 IAM 역할을 가져올 수도 있습니다.

   1. **프라이빗 API 구성**에서 프라이빗 API 기능을 활성화할 수 있습니다. 단, 병합된 API를 생성한 후에는 이 선택을 변경할 수 없습니다. 프라이빗 API에 대한 자세한 내용은 [AWS AppSync 프라이빗 API 사용](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html)을 참조하세요.

      완료했으면 **다음**을 선택합니다.

1. 다음으로 병합된 API의 기반으로 사용할 GraphQL API를 추가해야 합니다. **소스 API 선택** 페이지에서 다음 정보를 입력합니다.

   1. ** AWS 계정 테이블의 APIs에서** **소스 APIs** 선택합니다. GraphQL API 목록의 각 항목에는 다음 데이터가 포함됩니다.

      1. **이름**: GraphQL API의 **API 이름** 필드입니다.

      1. **API ID**: GraphQL API의 고유한 ID 값입니다.

      1. **기본 인증 모드**: GraphQL API의 기본 권한 부여 모드입니다. AWS AppSync의 권한 부여 모드에 대한 자세한 내용은 [권한 부여 및 인증](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html)을 참조하세요.

      1. **추가 인증 모드**: GraphQL API에 구성된 보조 권한 부여 모드입니다.

      1. API의 **이름** 필드 옆에 있는 확인란을 선택하여 병합된 API에서 사용할 API를 선택합니다. 그런 다음 **소스 API 추가**를 선택합니다. 선택한 GraphQL API는 ** AWS 계정의 API** 테이블에 표시됩니다.

   1. **다른 AWS 계정의 APIs 테이블에서** **소스 APIs** 선택합니다. 이 목록의 GraphQL APIs는 AWS Resource Access Manager ()를 통해 리소스를 공유하는 다른 계정에서 가져옵니다AWS RAM. 이 테이블의 GraphQL API를 선택하는 프로세스는 이전 섹션의 프로세스와 동일합니다. 를 통한 리소스 공유에 대한 자세한 내용은 란 무엇입니까?를 AWS RAM참조하세요. [AWS Resource Access Manager](https://docs.aws.amazon.com/ram/latest/userguide/what-is.html) 

      완료했으면 **다음**을 선택합니다.

   1. 기본 인증 모드를 추가합니다. 자세한 내용은 [권한 부여 및 인증](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html)을 참조하세요. **다음**을 선택합니다.

   1. 입력 내용을 검토한 다음 **API 생성**을 선택합니다.

# RDS 내부 검사를 통한 GraphQL API 빌드
<a name="rds-introspection"></a>

AWS AppSync의 내부 검사 유틸리티는 데이터베이스 테이블에서 모델을 검색하고 GraphQL 유형을 제안할 수 있습니다. AWS AppSync 콘솔의 API 생성 마법사는 Aurora MySQL 또는 PostgreSQL 데이터베이스에서 API를 즉시 생성할 수 있습니다. 데이터를 읽고 쓸 수 있는 유형과 JavaScript 해석기를 자동으로 생성합니다.

AWS AppSync 는 Amazon RDS Data API를 통해 Amazon Aurora 데이터베이스와 직접 통합합니다. Amazon RDS Data API는 영구 데이터베이스 연결이 필요한 대신 SQL 문 실행을 위해에 AWS AppSync 연결하는 보안 HTTP 엔드포인트를 제공합니다. 이를 사용하여 Aurora에서 MySQL 및 PostgreSQL 워크로드를 위한 관계형 데이터베이스 API를 생성할 수 있습니다.

를 사용하여 관계형 데이터베이스용 API를 빌드하면 다음과 같은 몇 가지 이점 AWS AppSync 이 있습니다.
+ 데이터베이스는 액세스 포인트를 데이터베이스 자체에서 분리하므로 클라이언트에 직접 노출되지 않습니다.
+ 다양한 애플리케이션의 요구 사항에 맞게 특별히 구축된 API를 구축할 수 있으므로 프런트엔드에서 사용자 지정 비즈니스 로직이 필요하지 않습니다. 이는 Backend-For-Frontend(BFF) 패턴과 일치합니다.
+ 다양한 권한 부여 모드를 사용하여 AWS AppSync 계층에서 권한 부여 및 액세스 제어를 구현하여 액세스를 제어할 수 있습니다. 웹 서버 호스팅 또는 프록시 연결과 같이 데이터베이스에 연결하는 데 추가 컴퓨팅 리소스가 필요하지 않습니다.
+ 구독을 통해 실시간 기능을 추가할 수 있으며, AppSync를 통해 이루어진 데이터 변경은 연결된 클라이언트에 자동으로 푸시됩니다.
+ 클라이언트는 443과 같은 일반 포트를 사용하여 HTTPS를 통해 API에 연결할 수 있습니다.

AWS AppSync 를 사용하면 기존 관계형 데이터베이스에서 APIs 쉽게 빌드할 수 있습니다. 내부 검사 유틸리티는 데이터베이스 테이블에서 모델을 검색하고 GraphQL 유형을 제안할 수 있습니다. AWS AppSync 콘솔의 *API 생성* 마법사는 Aurora MySQL 또는 PostgreSQL 데이터베이스에서 API를 즉시 생성할 수 있습니다. 데이터를 읽고 쓸 수 있는 유형과 JavaScript 해석기를 자동으로 생성합니다.

AWS AppSync 는 해석기에서 SQL 문 작성을 간소화하는 통합 JavaScript 유틸리티를 제공합니다. 동적 값이 있는 정적 문에 AWS AppSync의 `sql` 태그 템플릿을 사용하거나 `rds` 모듈 유틸리티를 사용하여 프로그래밍 방식으로 문을 빌드할 수 있습니다. 자세한 내용은 [RDS용 해석기 함수 참조](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-reference-rds-js.html) 데이터 소스 및 [내장 모듈](https://docs.aws.amazon.com//appsync/latest/devguide/built-in-modules-js.html#built-in-rds-modules) 섹션을 참조하십시오.

## 내부 검사 기능 사용(콘솔)
<a name="using-introspection-console"></a>

자세한 자습서 및 시작하기 안내서는 [자습서: 데이터 API를 사용하는 Aurora PostgreSQL Serverless](https://docs.aws.amazon.com//appsync/latest/devguide/aurora-serverless-tutorial-js.html) 섹션을 참조하십시오.

 AWS AppSync 콘솔을 사용하면 몇 분 만에 데이터 API로 구성된 기존 Aurora 데이터베이스에서 AWS AppSync GraphQL API를 생성할 수 있습니다. 그러면 데이터베이스 구성을 기반으로 운영 스키마가 빠르게 생성됩니다. API를 있는 그대로 사용하거나 API를 기반으로 기능을 추가할 수 있습니다.

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **대시보드**에서 **API 생성**을 선택합니다.

1. **API 옵션**에서 **GraphQL API**를 선택하고 **Amazon Aurora 클러스터로 시작**을 누른 다음 **다음**을 선택합니다.

   1. **API 이름**을 입력합니다. 이는 콘솔에서 API의 식별자로 사용됩니다.

   1. **연락처 세부 정보**에는 API 관리자를 식별할 연락처를 입력하면 됩니다. 이 필드는 선택 사항입니다.

   1. **프라이빗 API 구성**에서 프라이빗 API 기능을 활성화할 수 있습니다. 프라이빗 API는 구성된 VPC 엔드포인트(VPCE)에서만 액세스할 수 있습니다. 자세한 내용은 [프라이빗 API](https://docs.aws.amazon.com//appsync/latest/devguide/using-private-apis.html)를 참조하세요.

      이 예에서는 이 기능을 활성화하지 않는 것이 좋습니다. 입력 내용을 검토한 후 **다음**을 선택합니다.

1. **데이터베이스** 페이지에서 **데이터베이스 선택**을 선택합니다.

   1. 클러스터에서 데이터베이스를 선택해야 합니다. 첫 번째 단계는 클러스터가 있는 **리전**을 선택하는 것입니다.

   1. 드롭다운 목록에서 **Aurora 클러스터**를 선택합니다. 리소스를 사용하기 전에 해당 데이터 API를 생성하고 [활성화](https://docs.aws.amazon.com//AmazonRDS/latest/AuroraUserGuide/data-api.html#data-api.enabling)해야 합니다.

   1. 다음으로 데이터베이스에 대한 보안 인증을 서비스에 추가해야 합니다. 이 작업은 주로를 사용하여 수행됩니다 AWS Secrets Manager. 암호가 존재하는 **리전**을 선택합니다. 암호 정보를 검색하는 방법에 대한 자세한 내용은 [보안 암호 찾기](https://docs.aws.amazon.com//secretsmanager/latest/userguide/manage_search-secret.html) 또는 [보안 암호 검색](https://docs.aws.amazon.com//secretsmanager/latest/userguide/retrieving-secrets.html)을 참조하십시오.

   1. 드롭다운 목록에서 암호를 추가합니다. 단, 사용자에게 데이터베이스에 대한 [읽기 권한](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/security_iam_id-based-policy-examples.html#security_iam_id-based-policy-examples-console)이 있어야 합니다.

1. **가져오기**를 선택합니다.

   AWS AppSync 는 데이터베이스 내부 검사, 테이블, 열, 기본 키 및 인덱스 검색을 시작합니다. 검색된 테이블이 GraphQL API에서 지원될 수 있는지 확인합니다. 새 행 생성을 지원하려면 테이블에 여러 열을 사용할 수 있는 기본 키가 필요합니다.는 테이블 열을 AWS AppSync 매핑하여 다음과 같이 필드를 입력합니다.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/rds-introspection.html)

1. 테이블 검색이 완료되면 **데이터베이스** 섹션에 사용자 정보가 채워집니다. 새 **데이터베이스 테이블** 섹션에서 테이블의 데이터가 이미 채워져 스키마의 유형으로 변환되었을 수 있습니다. 필수 데이터 중 일부가 보이지 않는 경우 **테이블 추가**를 선택하고 나타나는 모달에서 해당 유형의 확인란을 클릭한 다음 **추가**를 선택하여 해당 데이터를 확인할 수 있습니다.

   **데이터베이스 테이블** 섹션에서 유형을 제거하려면 제거하려는 유형 옆의 확인란을 클릭한 다음 **제거**를 선택합니다. 제거된 유형은 나중에 다시 추가하려는 경우 **테이블 추가** 모달에 배치됩니다.

   는 테이블 이름을 유형 이름으로 AWS AppSync 사용하지만 이름을 바꿀 수 있습니다. 예를 들어 *영화*와 같은 복수 테이블 이름을 영화 유형 이름으로 변경할 수 있습니다**. **데이터베이스 테이블** 섹션에서 유형의 이름을 바꾸려면 이름을 바꾸려는 유형의 확인란을 클릭한 다음 **유형 이름** 열에서 *연필* 아이콘을 클릭합니다.

   선택에 따라 스키마의 내용을 미리 보려면 **스키마 미리 보기**를 선택합니다. 이 스키마는 비워 둘 수 없으므로 한 개 이상의 테이블을 유형으로 변환해야 합니다. 또한 이 스키마의 크기는 1MB를 초과할 수 없습니다.

   1. **서비스 역할**에서 이 가져오기를 위한 새 서비스 역할을 만들지 아니면 기존 역할을 사용할지를 선택합니다.

1. **다음**을 선택합니다.

1. 그런 다음 읽기 전용 API(쿼리만 해당)를 만들지 아니면 데이터 읽기 및 쓰기를 위한 API(쿼리 및 변형 해당)를 만들지 선택합니다. 후자는 변형에 의해 트리거되는 실시간 구독도 지원합니다.

1. **다음**을 선택합니다.

1. 선택 사항을 검토한 다음 **API 생성**을 선택합니다. AWS AppSync 는 API를 생성하고 해석기를 쿼리와 변형에 연결합니다. 생성된 API는 완벽하게 작동하며 필요에 따라 확장할 수 있습니다.

## 내부 검사 기능 사용(API)
<a name="using-introspection-api"></a>

`StartDataSourceIntrospection` 내부 검사 API를 사용하여 데이터베이스에서 프로그래밍 방식으로 모델을 검색할 수 있습니다. 명령에 대한 자세한 내용은 [https://docs.aws.amazon.com//appsync/latest/APIReference/API_StartDataSourceIntrospection.html](https://docs.aws.amazon.com//appsync/latest/APIReference/API_StartDataSourceIntrospection.html) API 사용 섹션을 참조하십시오.

를 사용하려면 Aurora 클러스터 Amazon 리소스 이름(ARN), 데이터베이스 이름 및 AWS Secrets Manager 보안 암호 ARN을 `StartDataSourceIntrospection`제공합니다. 이 명령은 내부 검사 프로세스를 시작합니다. `GetDataSourceIntrospection` 명령을 사용하여 결과를 검색할 수 있습니다. 검색된 모델의 스토리지 정의 언어(SDL) 문자열을 명령으로 반환할지 여부를 지정할 수 있습니다. 이는 검색된 모델에서 직접 SDL 스키마 정의를 생성하는 데 유용합니다.

 예를 들어, 단순 `Todos` 테이블에 다음과 같은 데이터 정의 언어(DDL) 문이 있는 경우

```
create table if not exists public.todos  
(  
id serial constraint todos_pk primary key,  
description text,  
due timestamp,  
"createdAt" timestamp default now()  
);
```

내부 검사는 다음과 같이 시작합니다.

```
aws appsync start-data-source-introspection \ 
  --rds-data-api-config resourceArn=<cluster-arn>,secretArn=<secret-arn>,databaseName=database
```

그런 다음 `GetDataSourceIntrospection` 명령을 사용하여 결과를 검색합니다.

```
aws appsync get-data-source-introspection \
  --introspection-id a1234567-8910-abcd-efgh-identifier \
  --include-models-sdl
```

그 결과 다음 결과를 반환합니다.

```
{
    "introspectionId": "a1234567-8910-abcd-efgh-identifier",
    "introspectionStatus": "SUCCESS",
    "introspectionStatusDetail": null,
    "introspectionResult": {
        "models": [
            {
                "name": "todos",
                "fields": [
                    {
                        "name": "description",
                        "type": {
                            "kind": "Scalar",
                            "name": "String",
                            "type": null,
                            "values": null
                        },
                        "length": 0
                    },
                    {
                        "name": "due",
                        "type": {
                            "kind": "Scalar",
                            "name": "AWSDateTime",
                            "type": null,
                            "values": null
                        },
                        "length": 0
                    },
                    {
                        "name": "id",
                        "type": {
                            "kind": "NonNull",
                            "name": null,
                            "type": {
                                "kind": "Scalar",
                                "name": "Int",
                                "type": null,
                                "values": null
                            },
                            "values": null
                        },
                        "length": 0
                    },
                    {
                        "name": "createdAt",
                        "type": {
                            "kind": "Scalar",
                            "name": "AWSDateTime",
                            "type": null,
                            "values": null
                        },
                        "length": 0
                    }
                ],
                "primaryKey": {
                    "name": "PRIMARY_KEY",
                    "fields": [
                        "id"
                    ]
                },
                "indexes": [],
                "sdl": "type todos\n{\ndescription: String\n\ndue: AWSDateTime\n\nid: Int!\n\ncreatedAt: AW
SDateTime\n}\n"
            }
        ],
        "nextToken": null
    }
}
```