

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

# AWS AppSync JavaScript 해석기 개요
<a name="resolver-reference-overview-js"></a>

AWS AppSync를 사용하면 데이터 소스에 대한 작업을 수행하여 GraphQL 요청에 응답할 수 있습니다. 쿼리, 뮤테이션 또는 구독을 실행하려는 각 GraphQL 필드에 대해 해석기를 첨부해야 합니다.

해석기는 GraphQL과 데이터 소스를 연결하는 커넥터입니다. 수신되는 GraphQL 요청을 백엔드 데이터 소스에 대한 지침으로 변환하는 방법과 해당 데이터 소스의 응답을 다시 GraphQL 응답으로 변환하는 방법을 AWS AppSync에 알려줍니다. AWS AppSync를 사용하면 JavaScript를 사용하여 해석기를 작성하고 AWS AppSync(`APPSYNC_JS`) 환경에서 실행할 수 있습니다.

AWS AppSync를 사용하면 파이프라인에서 여러 AWS AppSync 함수로 구성된 단위 해석기 또는 파이프라인 해석기를 작성할 수 있습니다.

## 지원되는 런타임 기능
<a name="runtime-support-js"></a>

 AWS AppSync JavaScript 런타임은 JavaScript 라이브러리, 유틸리티 및 기능의 하위 집합을 제공합니다. `APPSYNC_JS` 런타임에서 지원되는 전체 기능 목록은 [해석기 및 함수에 대한 JavaScript 런타임 기능](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)을 참조하세요.

## 유닛 해석기
<a name="unit-resolver-js"></a>

유닛 해석기는 데이터 소스에 대해 실행되는 요청 및 응답 핸들러를 정의하는 코드로 구성됩니다. 요청 핸들러는 컨텍스트 객체를 인수로 사용하고 데이터 소스를 호출하는 데 사용된 요청 페이로드를 반환합니다. 응답 핸들러는 실행된 요청의 결과와 함께 데이터 소스로부터 페이로드를 다시 받습니다. 응답 핸들러는 페이로드를 GraphQL 응답으로 변환하여 GraphQL 필드를 해결합니다. 아래 예제에서 해석기는 DynamoDB 데이터 소스에서 항목을 검색합니다.

```
import * as ddb from '@aws-appsync/utils/dynamodb'

export function request(ctx) {
  return ddb.get({ key: { id: ctx.args.id } });
}

export const response = (ctx) => ctx.result;
```

## JavaScript 파이프라인 해석기의 구조
<a name="anatomy-of-a-pipeline-resolver-js"></a>

파이프라인 해석기는 요청 핸들러 및 응답 핸들러와 함수 목록을 정의하는 코드로 구성됩니다. 각 함수에는 데이터 소스에 대해 실행되는 **요청** 및 **응답** 핸들러가 있습니다. 파이프라인 해석기는 함수 목록에 실행을 위임하기 때문에 자신은 어떠한 데이터 소스에도 연결되지 않습니다. 유닛 해석기와 함수는 데이터 원본에 대해 작업을 실행하는 기본 요소입니다.

### 파이프라인 해석기 요청 핸들러
<a name="request-handler-js"></a>

이 파이프라인 해석기의 요청 핸들러(이전 단계)를 사용하면 정의된 함수를 실행하기 전에 몇 가지 준비 로직을 수행할 수 있습니다.

### 함수 목록
<a name="functions-list-js"></a>

파이프라인 해석기가 순서대로 실행하는 함수 목록입니다. 파이프라인 해석기 요청 핸들러 평가 결과는 첫 번째 함수에 `ctx.prev.result`로 사용할 수 있습니다. 각 함수 평가 결과는 다음 함수에 `ctx.prev.result`로 사용할 수 있습니다.

### 파이프라인 해석기 응답 핸들러
<a name="response-handler-js"></a>

이 파이프라인 해석기의 응답 핸들러를 사용하면 마지막 함수의 출력에서 예상 GraphQL 필드 유형으로 몇 가지 최종 로직을 수행할 수 있습니다. 함수 목록의 마지막 함수 출력은 파이프라인 해석기 응답 핸들러에서 `ctx.prev.result` 또는 `ctx.result`로 사용할 수 있습니다.

### 실행 흐름
<a name="execution-flow-js"></a>

함수 2개로 구성된 파이프라인 해석기의 경우, 아래 목록은 해석기 간접 호출 시 실행 흐름을 나타냅니다.

1.  파이프라인 해석기 요청 핸들러

1.  함수 1: 함수 요청 핸들러 

1.  함수 1: 데이터 원본 호출 

1.  함수 1: 함수 응답 핸들러 

1.  함수 2: 함수 요청 핸들러 

1.  함수 2: 데이터 원본 호출 

1.  함수 2: 함수 응답 핸들러 

1.  파이프라인 해석기 응답 핸들러 

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


### 유용한 `APPSYNC_JS` 런타임 내장 유틸리티
<a name="useful-utilities-js"></a>

다음 유틸리티는 파이프라인 해석기로 작업할 때 유용할 수 있습니다.

#### ctx.stash
<a name="ctx-stash-js"></a>

stash는 각 해석기 및 함수 요청 및 응답 핸들러 내에서 사용할 수 있는 객체입니다. 단일 해석기가 실행되는 동안에는 동일한 stash 인스턴스가 사용됩니다. 즉, stash를 사용하여 요청 및 응답 핸들러와 파이프라인 해석기의 함수 간에 임의의 데이터를 전달할 수 있습니다. 정규 JavaScript 객체처럼 stash를 테스트할 수 있습니다.

#### ctx.prev.result
<a name="ctx-prev-result-js"></a>

`ctx.prev.result`는 파이프라인에서 실행된 이전 작업의 결과를 나타냅니다. 이전 작업이 파이프라인 해석기 요청 처리기였던 경우, `ctx.prev.result`는 체인의 첫 번째 함수에서 사용할 수 있게 됩니다. 이전 작업이 첫 번째 함수였으면 `ctx.prev.result`는 첫 번째 함수의 결과를 나타내고, 파이프라인의 두 번째 함수에 사용할 수 있습니다. 이전 작업이 마지막 함수였으면 `ctx.prev.result`는 마지막 함수의 결과를 나타내고, 파이프라인 해석기 응답 핸들러에 사용할 수 있습니다.

#### util.error
<a name="util-error-js"></a>

`util.error` 유틸리티는 필드 오류를 발생시키는 데 유용합니다. 함수 요청 또는 응답 핸들러 내에서 `util.error`를 사용하면 즉시 필드 오류가 발생해 후속 함수가 실행되지 않도록 방지합니다. 자세한 내용과 기타 `util.error` 서명을 보려면 [해석기 및 함수에 대한 JavaScript 런타임 기능](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)을 방문하세요.

#### util.appendError
<a name="util-appenderror-js"></a>

`util.appendError`는 `util.error()`와 유사하지만 핸들러 평가를 중단하지 않는다는 큰 차이점이 있습니다. 대신 필드에 오류가 있다는 신호를 보내지만 핸들러가 계속해서 평가되도록 하고 이어서 데이터를 반환합니다. 함수 내에서 `util.appendError`를 사용하면 파이프라인의 실행 흐름이 중단되지 않습니다. 자세한 내용과 기타 `util.error` 서명을 보려면 [해석기 및 함수에 대한 JavaScript 런타임 기능](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)을 방문하세요.

#### runtime.earlyReturn
<a name="runtime-earlyreturn-js"></a>

이 `runtime.earlyReturn` 함수를 사용하면 모든 요청 함수에서 조기에 반환할 수 있습니다. `runtime.earlyReturn`을 해석기 요청 핸들러 내에서 사용하면 해석기에서 반환됩니다. AWS AppSync 함수 요청 핸들러에서 호출하면 함수에서 반환되어 파이프라인의 다음 함수 또는 해석기 응답 핸들러로 계속 실행됩니다.

### 파이프라인 해석기 작성
<a name="writing-resolvers"></a>

파이프라인 해석기에는 파이프라인의 함수 실행을 둘러싼 요청 및 응답 핸들러도 있습니다. 요청 핸들러는 첫 번째 함수 요청 전에 실행되고, 응답 핸들러는 마지막 함수 응답 후에 실행됩니다. 해석기 요청 핸들러는 파이프라인의 함수에서 사용할 데이터를 설정할 수 있습니다. 해석기 응답 핸들러는 GraphQL 필드 출력 유형에 매핑되는 데이터를 반환하는 역할을 합니다. 아래 예에서 해석기 요청 처리기는 `allowedGroups`를 정의합니다. 반환된 데이터는 이러한 그룹 중 하나에 속해야 합니다. 이 값은 해석기의 함수에서 데이터를 요청하는 데 사용할 수 있습니다. 해석기의 응답 핸들러는 최종 검사를 수행하고 결과를 필터링하여 허용된 그룹에 속한 항목만 반환되도록 합니다.

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

/**
 * Called before the request function of the first AppSync function in the pipeline.
 *  @param ctx the context object holds contextual information about the function invocation.
 */
export function request(ctx) {
  ctx.stash.allowedGroups = ['admin'];
  ctx.stash.startedAt = util.time.nowISO8601();
  return {};
}
/**
 * Called after the response function of the last AppSync function in the pipeline.
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
  const result = [];
  for (const item of ctx.prev.result) {
    if (ctx.stash.allowedGroups.indexOf(item.group) > -1) result.push(item);
  }
  return result;
}
```

#### AWS AppSync 함수 작성
<a name="writing-functions"></a>

AWS AppSync 함수를 사용하면 스키마의 여러 해석기에서 재사용할 수 있는 공통 로직을 작성할 수 있습니다. 예를 들어 Amazon DynamoDB 데이터 소스에서 항목을 쿼리`QUERY_ITEMS`하는 역할을 하는 라는 one AWS AppSync 함수가 있을 수 있습니다. 항목을 쿼리하려는 해석기의 경우 해석기의 파이프라인에 함수를 추가하고 사용할 쿼리 색인을 제공하면 됩니다. 로직을 다시 구현할 필요는 없습니다.

## 추가 주제
<a name="supplemental-topics"></a>

**주제**
+ [Amazon DynamoDB를 사용한 파이프라인 해석기 예제](https://docs.aws.amazon.com/appsync/latest/devguide/writing-code.html)
+ [`APPSYNC_JS` 런타임의 유틸리티 구성](https://docs.aws.amazon.com/appsync/latest/devguide/utility-resolvers.html)
+ [`APPSYNC_JS` 런타임용 번들링, TypeScript 및 소스 맵](https://docs.aws.amazon.com/appsync/latest/devguide/additional-utilities.html)
+ [해석기 및 함수 핸들러 테스트](https://docs.aws.amazon.com/appsync/latest/devguide/test-resolvers.html)
+ [VTL에서 JavaScript로 마이그레이션](https://docs.aws.amazon.com/appsync/latest/devguide/migrating-resolvers.html)
+ [직접 데이터 소스 액세스와 Lambda 데이터 소스를 통한 프록시 중 선택](https://docs.aws.amazon.com/appsync/latest/devguide/choosing-data-source.html)

# Amazon DynamoDB를 사용한 파이프라인 해석기 예제
<a name="writing-code"></a>

다음 GraphQL 쿼리를 사용하여 Amazon DynamoDB 데이터 소스에서 `Post` 유형을 반환하는 `getPost(id:ID!)`라는 필드에 파이프라인 해석기를 연결한다고 가정해 보겠습니다.

```
getPost(id:1){
    id
    title
    content
}
```

먼저 아래 코드를 사용하여 간단한 해석기를 `Query.getPost`에 연결합니다. 다음은 간단한 해석기 코드의 예입니다. 요청 핸들러에는 로직이 정의되어 있지 않으며, 응답 핸들러는 단순히 마지막 함수의 결과를 반환합니다.

```
/**
 * Invoked **before** the request handler of the first AppSync function in the pipeline.
 * The resolver `request` handler allows to perform some preparation logic
 * before executing the defined functions in your pipeline.
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function request(ctx) {
  return {}
}

/**
 * Invoked **after** the response handler of the last AppSync function in the pipeline.
 * The resolver `response` handler allows to perform some final evaluation logic
 * from the output of the last function to the expected GraphQL field type.
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
  return ctx.prev.result
}
```

다음으로, 데이터 소스에서 사후 항목을 검색하는 함수 `GET_ITEM`을 정의합니다.

```
import { util } from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'

/**
 * Request a single item from the attached DynamoDB table datasource
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function request(ctx) {
	const { id } = ctx.args
	return ddb.get({ key: { id } })
}

/**
 * Returns the result
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
	const { error, result } = ctx
	if (error) {
		return util.appendError(error.message, error.type, result)
	}
	return ctx.result
}
```

요청 중에 오류가 발생하면 함수의 응답 핸들러가 GraphQL 응답에서 호출 클라이언트에 반환될 오류를 추가합니다. `GET_ITEM` 함수를 해석기 함수 목록에 추가합니다. 쿼리를 실행하면 `GET_ITEM` 함수의 요청 핸들러는 AWS AppSync의 DynamoDB 모듈에서 제공하는 유틸리티를 사용하여를 키`id`로 사용하여 `DynamoDBGetItem` 요청을 생성합니다.는 적절한 `GetItem` 작업을 `ddb.get({ key: { id } })` 생성합니다.

```
{
    "operation" : "GetItem",
    "key" : {
        "id" : { "S" : "1" }
    }
}
```

AWS AppSync 는 요청을 사용하여 Amazon DynamoDB에서 데이터를 가져옵니다. 데이터가 반환되면 `GET_ITEM` 함수의 응답 핸들러에서 처리되며, 이 핸들러는 오류를 확인한 다음 결과를 반환합니다.

```
{
  "result" : {
    "id": 1,
    "title": "hello world",
    "content": "<long story>"
  }
}
```

마지막으로, 해석기의 응답 핸들러는 결과를 직접 반환합니다.

## 오류 작업
<a name="working-with-errors"></a>

요청 중에 함수에서 오류가 발생하면 `ctx.error`의 함수 응답 핸들러에서 오류를 확인할 수 있습니다. `util.appendError` 유틸리티를 사용하여 GraphQL 응답에 오류를 추가할 수 있습니다. stash를 사용하여 파이프라인의 다른 함수에서 오류를 확인하도록 할 수 있습니다. 아래 예를 참조하세요.

```
/**
 * Returns the result
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
  const { error, result } = ctx;
  if (error) {
    if (!ctx.stash.errors) ctx.stash.errors = []
    ctx.stash.errors.push(ctx.error)
    return util.appendError(error.message, error.type, result);
  }
  return ctx.result;
}
```

# `APPSYNC_JS` 런타임의 유틸리티 구성
<a name="utility-resolvers"></a>

AWS AppSync 는 `APPSYNC_JS` 런타임으로 해석기를 개발하는 데 도움이 되는 두 개의 라이브러리를 제공합니다.
+ `@aws-appsync/eslint-plugin` - 개발 중에 문제를 빠르게 발견하고 수정합니다.
+ `@aws-appsync/utils` - 코드 편집기에서 유형 검증 및 자동 완성 기능을 제공합니다.

## eslint 플러그인 구성
<a name="utility-resolvers-configuring-eslint-plugin"></a>

[ESLint](https://eslint.org/)는 코드를 정적으로 분석하여 문제를 빠르게 찾아내는 도구입니다. 지속적인 통합 파이프라인의 일부로 ESLint를 실행할 수 있습니다. `@aws-appsync/eslint-plugin`은 `APPSYNC_JS` 런타임을 활용할 때 코드에서 잘못된 구문을 찾아내는 ESLint 플러그인입니다. 플러그인을 사용하면 변경 내용을 클라우드로 푸시하지 않고도 개발 중에 코드에 대한 피드백을 빠르게 받을 수 있습니다.

`@aws-appsync/eslint-plugin`은 개발 중에 사용할 수 있는 두 가지 규칙 세트를 제공합니다.

**"plugin:@aws-appsync/base"**는 프로젝트에서 활용할 수 있는 다음 기본 규칙 세트를 구성합니다.


| 규칙 | 설명 | 
| --- | --- | 
| no-async | 비동기식 프로세스 및 약속은 지원되지 않습니다. | 
| no-await | 비동기식 프로세스 및 약속은 지원되지 않습니다. | 
| no-classes | 클래스는 지원되지 않습니다. | 
| no-for | for는 지원되지 않습니다(for-in 및 for-of는 지원되는 경우 제외). | 
| no-continue | continue는 지원되지 않습니다. | 
| no-generators | 생성기는 지원되지 않습니다. | 
| no-yield | yield는 지원되지 않습니다. | 
| no-labels | 레이블은 지원되지 않습니다. | 
| no-this | this 키워드는 지원되지 않습니다. | 
| no-try | Try/catch 구조는 지원되지 않습니다. | 
| no-while | while 루프는 지원되지 않습니다. | 
| no-disallowed-unary-operators | \$1\$1, -- 및 \$1 단항 연산자는 허용되지 않습니다. | 
| no-disallowed-binary-operators | instanceof 연산자는 허용되지 않습니다. | 
| no-promise | 비동기식 프로세스 및 약속은 지원되지 않습니다. | 

**"plugin:@aws-appsync/recommended"**는 몇 가지 추가 규칙을 제공하지만 프로젝트에 TypeScript 구성을 추가해야 합니다.


| 규칙 | 설명 | 
| --- | --- | 
| no-recursion | 재귀 함수 호출은 허용되지 않습니다. | 
| no-disallowed-methods | 일부 메서드는 허용되지 않습니다. 지원되는 내장 함수 전체 세트는 [참조](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)를 참조하세요. | 
| no-function-passing | 함수를 함수 인수로 함수에 전달하는 것은 허용되지 않습니다. | 
| no-function-reassign | 함수는 재할당할 수 없습니다. | 
| no-function-return | 함수는 함수의 반환값이 될 수 없습니다. | 

프로젝트에 플러그인을 추가하려면 [ESLint 시작하기](https://eslint.org/docs/latest/user-guide/getting-started#installation-and-usage)의 설치 및 사용 단계를 따르세요. 그런 다음 프로젝트 패키지 관리자(예: npm, Yarn 또는 pnpm)를 사용하여 프로젝트에 [플러그인](https://www.npmjs.com/package/@aws-appsync/eslint-plugin)을 설치합니다.

```
$ npm install @aws-appsync/eslint-plugin
```

`.eslintrc.{js,yml,json}` 파일에서 `extends` 속성에 **"plugin:@aws-appsync/base"** 또는 **"plugin:@aws-appsync/recommended"**를 추가합니다. 아래 코드 조각은 JavaScript의 기본 샘플 `.eslintrc` 구성입니다.

```
{
  "extends": ["plugin:@aws-appsync/base"]
}
```

**"plugin:@aws-appsync/recommended"** 규칙 세트를 사용하려면 필수 종속성을 설치하세요.

```
$ npm install -D @typescript-eslint/parser
```

그런 다음 `.eslintrc.js` 파일을 생성하려면:

```
{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2018,
    "project": "./tsconfig.json"
  },
  "extends": ["plugin:@aws-appsync/recommended"]
}
```

# `APPSYNC_JS` 런타임용 번들링, TypeScript 및 소스 맵
<a name="additional-utilities"></a>

TypeScript는 유형 안전 및 조기 오류 감지를 제공하여 AWS AppSync 개발을 개선합니다. TypeScript 코드를 `APPSYNC_JS` 런타임에 사용하기 전에 로컬로 작성하고 JavaScript로 트랜스파일할 수 있습니다. 이 프로세스는 TypeScript를 설치하고 `APPSYNC_JS` 환경에 tsconfig.json을 구성하는 것으로 시작됩니다. 그런 다음, esbuild와 같은 번들링 도구를 사용하여 코드를 컴파일하고 번들링할 수 있습니다. Amplify CLI는 GraphQL 스키마에서 유형을 생성하므로 해석기 코드에서 해당 유형을 사용할 수 있습니다.

해석기 및 함수 코드에서는 `APPSYNC_JS` 요구 사항을 준수하는 한 사용자 지정 라이브러리와 외부 라이브러리를 모두 활용할 수 있습니다. 번들링 도구는 코드를 단일 파일로 결합하여 사용할 수 있습니다 AWS AppSync. 디버깅을 돕기 위해 소스 맵을 포함할 수 있습니다.

## 라이브러리 활용 및 코드 번들링
<a name="using-external-libraries"></a>

해석기 및 함수 코드에서는 `APPSYNC_JS` 요구 사항을 준수하는 한 사용자 지정 라이브러리와 외부 라이브러리를 모두 활용할 수 있습니다. 이렇게 하면 애플리케이션에서 기존 코드를 재사용할 수 있습니다. 여러 파일로 정의된 라이브러리를 사용하려면 [esbuild](https://esbuild.github.io/)와 같은 번들링 도구를 사용하여 코드를 단일 파일로 결합한 다음 AWS AppSync 해석기 또는 함수에 저장할 수 있습니다.

코드를 번들링할 때 다음 사항에 유의하세요.
+ `APPSYNC_JS`는 ECMAScript 모듈(ESM)만 지원합니다.
+ `@aws-appsync/*` 모듈은 `APPSYNC_JS`에 통합되므로 코드와 함께 번들로 제공해서는 안 됩니다.
+ `APPSYNC_JS` 런타임 환경은 코드가 브라우저 환경에서 실행되지 않는다는 점에서 NodeJS와 유사합니다.
+ 선택적 소스 맵을 포함할 수 있습니다. 그러나 소스 콘텐츠는 포함되지 마세요.

  소스 맵에 대한 자세한 내용은 [소스 맵 사용](#source-maps)을 참조하세요.

예를 들어 `src/appsync/getPost.resolver.js`에 있는 해석기 코드를 번들로 묶으려면 다음 esbuild CLI 명령을 사용하면 됩니다.

```
$ esbuild --bundle \
--sourcemap=inline \
--sources-content=false \
--target=esnext \
--platform=node \
--format=esm \
--external:@aws-appsync/utils \
--outdir=out/appsync \
 src/appsync/getPost.resolver.js
```

## 코드 작성 및 TypeScript로 작업하기
<a name="working-with-typescript"></a>

[TypeScript](https://www.typescriptlang.org/)는 Microsoft에서 개발한 프로그래밍 언어로, TypeScript 타이핑 시스템과 함께 JavaScript의 모든 기능을 제공합니다. TypeScript를 사용하여 type-safe 코드를 작성하고 코드를 AWS AppSync에 저장하기 전에 빌드 시 오류와 버그를 잡을 수 있습니다. `@aws-appsync/utils` 패키지가 완전히 입력되었습니다.

`APPSYNC_JS` 런타임은 TypeScript를 직접 지원하지 않습니다. 코드를 AWS AppSync에 저장하기 전에 먼저 TypeScript 코드를 `APPSYNC_JS` 런타임이 지원하는 JavaScript 코드로 변환해야 합니다. TypeScript를 사용하여 로컬 통합 개발 환경(IDE)에서 코드를 작성할 수 있지만 AWS AppSync 콘솔에서는 TypeScript 코드를 생성할 수 없습니다.

시작하려면 프로젝트에 [TypeScript](https://www.typescriptlang.org/download)가 설치되어 있는지 확인하세요. 그런 다음 [TSConfig](https://www.typescriptlang.org/tsconfig)를 사용하여 `APPSYNC_JS` 런타임에서 작동하도록 TypeScript 트랜스컴파일 설정을 구성합니다. 사용할 수 있는 기본 `tsconfig.json` 파일의 예는 다음과 같습니다.

```
// tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
   "noEmit": true,
   "moduleResolution": "node",
  }
}
```

그런 다음 esbuild와 같은 번들링 도구를 사용하여 코드를 컴파일하고 번들링할 수 있습니다. 예를 들어 AWS AppSync 코드가에 있는 프로젝트의 `src/appsync`경우 다음 명령을 사용하여 코드를 컴파일하고 번들링할 수 있습니다.

```
$ esbuild --bundle \
--sourcemap=inline \
--sources-content=false \
--target=esnext \
--platform=node \
--format=esm \
--external:@aws-appsync/utils \
--outdir=out/appsync \
 src/appsync/**/*.ts
```

### Amplify codegen 사용
<a name="working-with-amplify-codegen"></a>

[Amplify CLI](https://docs.amplify.aws/cli/)를 사용하여 스키마의 유형을 생성할 수 있습니다. `schema.graphql` 파일이 있는 디렉터리에서 다음 명령을 실행하고 프롬프트를 검토하여 codegen을 구성합니다.

```
$  npx @aws-amplify/cli codegen add
```

특정 상황(예: 스키마 업데이트 시)에서 codegen을 재생성하려면 다음 명령을 실행합니다.

```
$ npx @aws-amplify/cli codegen
```

그런 다음 생성된 유형을 해석기 코드에 사용할 수 있습니다. 예를 들어 다음과 같은 스키마가 있습니다.

```
type Todo {
  id: ID!
  title: String!
  description: String
}

type Mutation {
  createTodo(title: String!, description: String): Todo
}

type Query {
  listTodos: Todo
}
```

다음 예제 AWS AppSync 함수에서 생성된 유형을 사용할 수 있습니다.

```
import { Context, util } from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
import { CreateTodoMutationVariables, Todo } from './API' // codegen

export function request(ctx: Context<CreateTodoMutationVariables>) {
	ctx.args.description = ctx.args.description ?? 'created on ' + util.time.nowISO8601()
	return ddb.put<Todo>({ key: { id: util.autoId() }, item: ctx.args })
}

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

### TypeScript에서 제네릭 사용
<a name="working-with-typescript-generics"></a>

제네릭을 제공된 여러 유형과 함께 사용할 수 있습니다. 예를 들어 아래 코드 조각은 `Todo` 유형입니다.

```
export type Todo = {
  __typename: "Todo",
  id: string,
  title: string,
  description?: string | null,
};
```

`Todo`를 사용하는 구독용 해석기를 작성할 수 있습니다. IDE에서 유형 정의 및 자동 완성 힌트는 `toSubscriptionFilter` 변환 유틸리티를 올바르게 사용하는 방법을 안내합니다.

```
import { util, Context, extensions } from '@aws-appsync/utils'
import { Todo } from './API'

export function request(ctx: Context) {
  return {}
}

export function response(ctx: Context) {
  const filter = util.transform.toSubscriptionFilter<Todo>({
    title: { beginsWith: 'hello' },
    description: { contains: 'created' },
  })
  extensions.setSubscriptionFilter(filter)
  return null
}
```

## 번들 린팅
<a name="using-lint-with-bundles"></a>

`esbuild-plugin-eslint` 플러그인을 가져와서 번들을 자동으로 린트할 수 있습니다. 그런 다음 eslint 기능을 활성화하는 `plugins` 값을 제공하여 활성화할 수 있습니다. 아래는 `build.mjs`라는 파일에서 esbuild JavaScript API를 사용하는 코드 조각입니다.

```
/* eslint-disable */
import { build } from 'esbuild'
import eslint from 'esbuild-plugin-eslint'
import glob from 'glob'
const files = await glob('src/**/*.ts')

await build({
  format: 'esm',
  target: 'esnext',
  platform: 'node',
  external: ['@aws-appsync/utils'],
  outdir: 'dist/',
  entryPoints: files,
  bundle: true,
  plugins: [eslint({ useEslintrc: true })],
})
```

## 소스 맵 사용
<a name="source-maps"></a>

JavaScript 코드로 인라인 소스 맵(`sourcemap`)을 제공할 수 있습니다. 소스 맵은 JavaScript 또는 TypeScript 코드를 번들로 제공하고 로그 및 런타임 JavaScript 오류 메시지에서 입력 소스 파일에 대한 참조를 확인하려는 경우에 유용합니다.

`sourcemap`은 코드 끝에 표시되어야 합니다. 이 코드는 다음 형식을 따르는 단일 주석 행으로 정의됩니다.

```
//# sourceMappingURL=data:application/json;base64,<base64 encoded string>
```

다음은 그 예입니다.

```
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsibGliLmpzIiwgImNvZGUuanMiXSwKICAibWFwcGluZ3MiOiAiO0FBQU8sU0FBUyxRQUFRO0FBQ3RCLFNBQU87QUFDVDs7O0FDRE8sU0FBUyxRQUFRLEtBQUs7QUFDM0IsU0FBTyxNQUFNO0FBQ2Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
```

esbuild를 사용하여 소스 맵을 생성할 수 있습니다. 아래 예제는 코드를 빌드하고 번들링할 때 esbuild JavaScript API를 사용하여 인라인 소스 맵을 포함하는 방법을 보여줍니다.

```
/* eslint-disable */
import { build } from 'esbuild'
import eslint from 'esbuild-plugin-eslint'
import glob from 'glob'
const files = await glob('src/**/*.ts')

await build({
  sourcemap: 'inline',
  sourcesContent: false,
  
  format: 'esm',
  target: 'esnext',
  platform: 'node',
  external: ['@aws-appsync/utils'],
  outdir: 'dist/',
  entryPoints: files,
  bundle: true,
  plugins: [eslint({ useEslintrc: true })],
})
```

특히 `sourcemap` 및 `sourcesContent` 옵션은 각 빌드가 끝날 때마다 소스 맵을 줄지어 추가하되 소스 콘텐츠는 포함하지 않도록 지정합니다. 규칙에 따라 소스 콘텐츠는 `sourcemap`에 포함하지 않는 것이 좋습니다. `sources-content`를 `false`로 설정하여 esbuild에서 이를 비활성화할 수 있습니다.

소스 맵의 작동 방식을 설명하려면 해석기 코드가 도우미 라이브러리의 도우미 함수를 참조하는 다음 예제를 검토하세요. 코드에는 해석기 코드와 도우미 라이브러리의 로그 명령문이 포함되어 있습니다.

**./src/default.resolver.ts**(사용자의 해석기)

```
import { Context } from '@aws-appsync/utils'
import { hello, logit } from './helper'

export function request(ctx: Context) {
  console.log('start >')
  logit('hello world', 42, true)
  console.log('< end')
  return 'test'
}

export function response(ctx: Context): boolean {
  hello()
  return ctx.prev.result
}
```

**.src/helper.ts**(도우미 파일)

```
export const logit = (...rest: any[]) => {
  // a special logger
  console.log('[logger]', ...rest.map((r) => `<${r}>`))
}

export const hello = () => {
  // This just returns a simple sentence, but it could do more.
  console.log('i just say hello..')
}
```

해석기 파일을 빌드하고 번들링하면 해석기 코드에 인라인 소스 맵이 포함됩니다. 해석기가 실행되면 CloudWatch 로그에 다음과 같은 항목이 나타납니다.

![\[CloudWatch log entries showing resolver code execution with inline source map information.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/cloudwatch-sourcemap.jpeg)


CloudWatch 로그의 항목을 살펴보면 두 파일의 기능이 함께 번들로 묶여 동시에 실행되고 있음을 알 수 있습니다. 각 파일의 원본 파일 이름도 로그에 명확하게 반영됩니다.

# 에서 해석기 및 함수 핸들러 테스트 AWS AppSync
<a name="test-resolvers"></a>

코드를 해석기 또는 함수에 저장하기 전에 `EvaluateCode` API 명령을 사용하여 모의 데이터로 해석기 및 함수 핸들러를 원격으로 테스트할 수 있습니다. 명령어를 시작하려면 정책에 `appsync:evaluatecode` 권한을 추가했는지 확인하세요. 예제:

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

****  

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

------

[AWS CLI](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/index.html) 또는 [AWS SDK](https://aws.amazon.com/tools/)를 사용하여 명령을 활용할 수 있습니다. 예를 들어 CLI를 사용하여 코드를 테스트하려면 파일을 가리키고, 컨텍스트를 제공하고, 평가할 핸들러를 지정하기만 하면 됩니다.

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

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

```
{
    "evaluationResult": "{\"operation\":\"PutItem\",\"key\":{\"id\":{\"S\":\"record-id\"}},\"attributeValues\":{\"owner\":{\"S\":\"John doe\"},\"expectedVersion\":{\"N\":2},\"authorId\":{\"S\":\"Sammy Davis\"}}}",
    "logs": [
        "INFO - code.js:5:3: \"current id\" \"record-id\"",
        "INFO - code.js:9:3: \"request evaluated\""
    ]
}
```

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

```
{
  "operation": "PutItem",
  "key": {
    "id": {
      "S": "record-id"
    }
  },
  "attributeValues": {
    "owner": {
      "S": "John doe"
    },
    "expectedVersion": {
      "N": 2
    },
    "authorId": {
      "S": "Sammy Davis"
    }
  }
}
```

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

# 에서 VTL에서 JavaScript로 마이그레이션 AWS AppSync
<a name="migrating-resolvers"></a>

AWS AppSync를 사용하면 VTL 또는 JavaScript를 사용하여 해석기 및 함수에 대한 비즈니스 로직을 작성할 수 있습니다. 두 언어를 모두 사용하면 AWS AppSync 서비스에 데이터 소스와 상호 작용하는 방법을 지시하는 로직을 작성할 수 있습니다. VTL을 사용하면 유효한 JSON으로 인코딩된 문자열로 평가되어야 하는 매핑 템플릿을 작성할 수 있습니다. JavaScript를 사용하면 객체를 반환하는 요청 핸들러 및 응답 핸들러를 작성할 수 있습니다. JSON으로 인코딩된 문자열은 반환하지 않습니다.

예를 들어, 다음 VTL 매핑 템플릿을 사용하여 Amazon DynamoDB 항목을 가져옵니다.

```
{
    "operation": "GetItem",
    "key": {
        "id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
    }
}
```

유틸리티 `$util.dynamodb.toDynamoDBJson`은 JSON으로 인코딩된 문자열을 반환합니다. `$ctx.args.id`가 `<id>`로 설정된 경우 템플릿은 유효한 JSON 인코딩 문자열로 평가됩니다.

```
{
    "operation": "GetItem",
    "key": {
        "id": {"S": "<id>"},
    }
}
```

JavaScript로 작업할 때 코드 내에서 원시 JSON 인코딩 문자열을 인쇄할 필요가 없으며 `toDynamoDBJson`과 같은 유틸리티를 사용할 필요가 없습니다. 위의 매핑 템플릿과 동일한 예제는 다음과 같습니다.

```
import { util } from '@aws-appsync/utils';
export function request(ctx) {
  return {
    operation: 'GetItem',
    key: {id: util.dynamodb.toDynamoDB(ctx.args.id)}
  };
}
```

대안은 값 객체를 처리하는 데 권장되는 접근 방식인 `util.dynamodb.toMapValues`를 사용하는 것입니다.

```
import { util } from '@aws-appsync/utils';
export function request(ctx) {
  return {
    operation: 'GetItem',
    key: util.dynamodb.toMapValues({ id: ctx.args.id }),
  };
}
```

이 결과는 다음과 같이 평가됩니다.

```
{
  "operation": "GetItem",
  "key": {
    "id": {
      "S": "<id>"
    }
  }
}
```

**참고**  
DynamoDB 모듈을 DynamoDB 데이터 소스와 함께 사용하는 것이 좋습니다.  

```
import * as ddb from '@aws-appsync/utils/dynamodb'

export function request(ctx) {
	ddb.get({ key: { id: ctx.args.id } })
}
```

또 다른 예로, 다음 매핑 템플릿을 사용하여 Amazon DynamoDB 데이터 소스에 항목을 입력합니다.

```
{
    "operation" : "PutItem",
    "key" : {
        "id": $util.dynamodb.toDynamoDBJson($util.autoId()),
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
```

평가 시 이 매핑 템플릿 문자열은 유효한 JSON 인코딩 문자열을 생성해야 합니다. JavaScript를 사용하는 경우 코드는 요청 객체를 직접 반환합니다.

```
import { util } from '@aws-appsync/utils';
export function request(ctx) {
  const { id = util.autoId(), ...values } = ctx.args;
  return {
    operation: 'PutItem',
    key: util.dynamodb.toMapValues({ id }),
    attributeValues: util.dynamodb.toMapValues(values),
  };
}
```

이는 다음과 같이 평가됩니다.

```
{
  "operation": "PutItem",
  "key": {
    "id": { "S": "2bff3f05-ff8c-4ed8-92b4-767e29fc4e63" }
  },
  "attributeValues": {
    "firstname": { "S": "Shaggy" },
    "age": { "N": 4 }
  }
}
```

**참고**  
DynamoDB 모듈을 DynamoDB 데이터 소스와 함께 사용하는 것이 좋습니다.  

```
import { util } from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'

export function request(ctx) {
	const { id = util.autoId(), ...item } = ctx.args
	return ddb.put({ key: { id }, item })
}
```

# 직접 데이터 소스 액세스와 Lambda 데이터 소스를 통한 프록시 중 선택
<a name="choosing-data-source"></a>

 AWS AppSync 및 `APPSYNC_JS` 런타임을 사용하면 AWS AppSync 함수를 사용하여 데이터 소스에 액세스하여 사용자 지정 비즈니스 로직을 구현하는 자체 코드를 작성할 수 있습니다. 따라서 추가 컴퓨팅 AWS 서비스 또는 인프라를 배포할 필요 없이 Amazon DynamoDB, Aurora Serverless, OpenSearch Service, HTTP APIs 및 기타 서비스와 같은 데이터 소스와 직접 상호 작용할 수 있습니다. 또한 AWS AppSync를 사용하면 Lambda 데이터 소스를 구성하여 AWS Lambda 함수와 쉽게 상호 작용할 수 있습니다. Lambda 데이터 소스를 사용하면 AWS Lambda의 전체 설정 기능을 사용하여 복잡한 비즈니스 로직을 실행하여 GraphQL 요청을 해결할 수 있습니다. 대부분의 경우 대상 데이터 소스에 직접 연결된 AWS AppSync 함수는 필요한 모든 기능을 제공합니다. `APPSYNC_JS` 런타임에서 지원하지 않는 복잡한 비즈니스 로직을 구현해야 하는 상황에서는 Lambda 데이터 소스를 프록시로 사용하여 대상 데이터 소스와 상호 작용할 수 있습니다.


|  |  |  | 
| --- |--- |--- |
|  | 직접 데이터 소스 통합 | 프록시로서의 Lambda 데이터 소스 | 
| 사용 사례: | AWS AppSync functions interact directly with API data sources. | AWS AppSync functions call Lambdas that interact with API data sources. | 
| Runtime | APPSYNC\$1JS(JavaScript) | 지원되는 Lambda 런타임 | 
| Maximum size of code |  AWS AppSync 함수당 32,000자 | Lambda당 50MB(직접 업로드용 압축 파일) | 
| External modules | 제한적 - APPSYNC\$1JS는 기능만 지원 | 예 | 
| Call any AWS service | 예 - AWS AppSync HTTP 데이터 소스 사용 | 예 - AWS SDK 사용 | 
| Access to the request header | 예 | 예 | 
| Network access | 아니요 | 예 | 
| File system access | 아니요 | 예 | 
| Logging and metrics | 예 | 예 | 
| Build and test entirely within AppSync | 예 | 아니요 | 
| Cold start | 아니요 | 아니요 - 프로비저닝된 동시성 | 
| Auto-scaling | 예 - AWS AppSync에서 투명하게 표시 | 예 - Lambda에서 구성한 대로 | 
| Pricing | 추가 요금 없음 | Lambda 사용에 대한 요금 부과 | 

대상 데이터 소스와 직접 통합되는AWS AppSync 함수는 다음과 같은 사용 사례에 적합합니다.
+  Amazon DynamoDB, Aurora Serverless 및 OpenSearch Service와의 상호 작용
+  HTTP API와의 상호 작용 및 수신 헤더 전달 
+  HTTP 데이터 소스를 사용하여 AWS 서비스와 상호 작용(제공된 데이터 소스 역할로 요청에 AWS AppSync 자동으로 서명) 
+  데이터 소스에 액세스하기 전에 액세스 제어 구현 
+  요청을 이행하기 전에 검색된 데이터에 대한 필터링 구현 
+  해석기 파이프라인에서 AWS AppSync 함수를 순차적으로 실행하여 간단한 오케스트레이션 구현 
+  쿼리와 뮤테이션의 캐싱 및 구독 연결 제어 

Lambda 데이터 소스를 프록시로 사용하는AWS AppSync 함수는 다음과 같은 사용 사례에 적합합니다.
+  JavaScript 또는 Velocity Template Language(VTL) 이외의 언어 사용 
+  CPU 또는 메모리를 조정 및 제어하여 성능 최적화 
+  타사 라이브러리를 가져오거나 `APPSYNC_JS`에서 지원되지 않는 기능을 요구 
+  여러 네트워크 요청 및/또는 쿼리 수행을 위한 파일 시스템 액세스 권한 얻기 
+  [일괄 처리 구성](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-lambda-js.html)을 사용한 요청 일괄 처리.