

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

# AWS AppSync 해석기 매핑 템플릿 프로그래밍 가이드
<a name="resolver-mapping-template-reference-programming-guide"></a>

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

Apache Velocity 템플릿 언어(VTL)를 사용한 프로그래밍에 대한 쿡북 스타일의 자습서입니다 AWS AppSync. JavaScript, C 또는 Java 같은 다른 프로그래밍에 대해 잘 알고 있다면 매우 쉬울 것입니다.

AWS AppSync는 VTL을 사용하여 클라이언트의 GraphQL 요청을 데이터 소스에 대한 요청으로 변환합니다. 그런 다음 이 프로세스를 역순으로 수행하여 데이터 원본 응답을 GraphQL 응답으로 다시 변환합니다. VTL은 다음과 같은 기술을 사용하여 웹 애플리케이션의 표준 요청/응답 흐름 요청과 응답을 둘 다 처리할 수 있는 논리적인 템플릿 언어입니다.
+ 새 항목의 기본값
+ 입력 확인 및 서식 지정
+ 데이터 변환 및 셰이핑
+ 목록, 맵 및 배열을 반복하여 값을 추출하거나 변경
+ 사용자 자격 증명 기반 응답 필터링/변경
+ 복잡한 권한 부여 검사

예를 들면 GraphQL 인수에서 서비스의 전화번호를 확인하거나 DynamoDB에 저장하기 전에 입력 파라미터를 대문자로 변환해야 할 수도 있습니다. 또는 클라이언트 시스템에서 GraphQL 인수, JWT 토큰 클레임 또는 HTTP 헤더에 코드를 포함시켜 제공하도록 하거나, 코드가 목록의 특정 문자열과 일치할 경우에만 데이터로 응답하도록 할 수 있습니다. 이는 모두 VTL in AWS AppSync로 수행할 수 있는 논리적 검사입니다.

VTL에서는 익숙한 프로그래밍 기술로 로직을 적용할 수 있습니다. 하지만 사용자 기반의 성장에 따라 GraphQL API를 확장하려면 표준 요청/응답 흐름 내에서만 실행해야 합니다. 또한 AWS AppSync는 해석기로를 지원 AWS Lambda 하므로 유연성이 더 필요한 경우 선택한 프로그래밍 언어(Node.js, Python, Go, Java 등)로 Lambda 함수를 작성할 수 있습니다.

## 설정
<a name="setup"></a>

언어 학습 시 사용하는 일반적인 기술 중 하나는 결과(예: JavaScript의 `console.log(variable)`)를 출력하여 어떻게 되는지 보는 것입니다. 이 자습서에서는 단순 GraphQL 스키마를 생성하고 값 맵을 Lambda 함수에 전달함으로써 이 기술을 설명합니다. Lambda 함수가 값을 출력하고 나서 값에 응답합니다. 따라서 요청/응답 흐름을 이해하고 다양한 프로그래밍 기법을 볼 수 있습니다.

다음 GraphQL 스키마를 생성하는 것부터 시작합니다.

```
type Query {
    get(id: ID, meta: String): Thing
}

type Thing {
    id: ID!
    title: String!
    meta: String
}

schema {
    query: Query
}
```

이제 Node.js를 언어로 사용하여 다음 AWS Lambda 함수를 생성합니다.

```
exports.handler = (event, context, callback) => {
    console.log('VTL details: ', event);
    callback(null, event);
};
```

 AWS AppSync 콘솔의 **데이터 소스** 창에서이 Lambda 함수를 새 데이터 소스로 추가합니다. 콘솔의 **스키마** 페이지로 돌아가서 오른쪽 `get(...):Thing` 쿼리 옆에 있는 **연결** 버튼을 클릭합니다. 요청 템플릿으로는 **Invoke and forward arguments(인수 호출 및 전달)** 메뉴에서 기존 템플릿을 선택합니다. 응답 템플릿으로는 **Lambda 결과 반환(Return Lambda result)**을 선택합니다.

Lambda 함수에 대한 Amazon CloudWatch Logs를 한 위치에서 열고 AWS AppSync 콘솔의 **쿼리** 탭에서 다음 GraphQL 쿼리를 실행합니다.

```
query test {
  get(id:123 meta:"testing"){
    id
    meta
  }
}
```

Lambda 함수가 `id:123` 및 `meta:testing`를 다시 되풀이하여 표시하므로 GraphQL 응답에 이 두 요소가 포함되어야 합니다. 몇 초 후에는 CloudWatch Logs에서 이러한 세부 정보와 함께 레코드를 볼 수 있습니다.

## 변수
<a name="variables"></a>

VTL은 [참조](https://velocity.apache.org/engine/1.7/user-guide.html#references)를 사용합니다. 이 참조는 데이터를 저장하거나 조작하는 데 사용할 수 있습니다. VTL에는 변수, 속성 및 메서드라는 세 가지 유형이 있습니다. 변수는 앞에 `$` 기호가 붙으며 `#set` 지시문을 사용하여 생성됩니다.

```
#set($var = "a string")
```

변수는 숫자, 문자열, 배열, 목록 및 맵 등 다른 언어에서 친숙한 유형과 비슷한 유형을 저장합니다. Lambda 해석기의 기본 요청 템플릿에서 JSON 페이로드가 전송됨을 눈치채셨을 것입니다.

```
"payload": $util.toJson($context.arguments)
```

여기에서 알아두어야 할 몇 가지 사항이 있습니다. 먼저 AWS AppSync는 일반적인 작업을 위한 몇 가지 편의 기능을 제공합니다. 이 예에서는 `$util.toJson`이 변수를 JSON으로 변환합니다. 두 번째, `$context.arguments` 변수가 GraphQL 요청에서 맵 객체로 자동 채워집니다. 다음과 같이 새 맵을 생성할 수 있습니다.

```
#set( $myMap = {
  "id": $context.arguments.id,
  "meta": "stuff",
  "upperMeta" : $context.arguments.meta.toUpperCase()
} )
```

이제 `$myMap`이라는 변수를 만들었으며, 이 변수에는 `id`, `meta` 및`upperMeta` 키가 있습니다. 이 코드는 몇 가지 다른 것도 보여줍니다.
+  `id`가 GraphQL 인수의 키로 채워집니다. VTL에서는 클라이언트의 인수를 가져오기 위해 일반적으로 이렇게 작동합니다.
+  `meta`가 기본값을 보여주는 값으로 하드코딩됩니다.
+  `upperMeta`가 `meta` 메서드를 사용하여 `.toUpperCase()` 인수로 변환됩니다.

요청 템플릿 맨 위에 이전 코드를 추가하고 `payload`를 새 `$myMap` 변수로 변경합니다.

```
"payload": $util.toJson($myMap)
```

Lambda 함수를 실행하고 나면 CloudWatch logs에서 응답 변경 내용은 물론 이 데이터도 확인할 수 있습니다. 이 자습서의 나머지를 진행하면서 비슷한 테스트를 실행할 수 있도록 `$myMap`을 채운 상태로 유지하겠습니다.

또한 변수에서 *properties\$1*를 설정할 수도 있습니다. 이러한 항목은 단순 문자열, 배열 또는 JSON입니다.

```
#set($myMap.myProperty = "ABC")
#set($myMap.arrProperty = ["Write", "Some", "GraphQL"])
#set($myMap.jsonProperty = {
    "AppSync" : "Offline and Realtime",
    "Cognito" : "AuthN and AuthZ"
})
```

### 자동 참조
<a name="quiet-references"></a>

VTL은 기본적으로 템플릿 언어이므로 개발자가 제공하는 모든 참조가 `.toString()`을 수행합니다. 참조가 정의되지 않은 경우 실제 참조 표현을 문자열로 출력합니다. 예제:

```
#set($myValue = 5)
##Prints '5'
$myValue

##Prints '$somethingelse'
$somethingelse
```

이를 해결하도록 VTL에 *quiet reference* 또는 *silent reference* 구문이 있으며, 이 구문은 템플릿 엔진에 이 동작을 숨기도록 지시합니다. 이에 대한 구문은 `$!{}`입니다. 예를 들어 `$!{somethingelse}`를 사용하도록 이전 코드를 조금 변경한 경우 출력이 표시되지 않습니다.

```
#set($myValue = 5)
##Prints '5'
$myValue

##Nothing prints out
$!{somethingelse}
```

## 메서드 직접 호출
<a name="calling-methods"></a>

이전 예제에서 변수를 생성하고 동시에 값을 설정하는 방법을 보여드렸습니다. 맵에 데이터를 추가하여 이 작업을 다음과 같이 두 단계로 수행할 수도 있었습니다.

```
#set ($myMap = {})
#set ($myList = [])

##Nothing prints out
$!{myMap.put("id", "first value")}
##Prints "first value"
$!{myMap.put("id", "another value")}
##Prints true
$!{myList.add("something")}
```

 **하지만** 이 동작에 대해 알아야 할 것이 있습니다. 위와 같이 자동 참조 표기 `$!{}`를 사용하여 메서드를 호출할 수 있더라도, 실행된 메서드의 반환 값은 숨길 수 없습니다. 위에서 `##Prints "first value"` 및 `##Prints true`를 사용한 이유는 바로 이 때문입니다. 이 문으로 키가 이미 존재하는 값을 삽입하는 등 맵이나 목록을 반복하려 할 때 오류가 발생할 수 있습니다. 출력이 평가 시 예기치 않은 문자열을 템플릿에 추가하기 때문입니다.

경우에 따라 `#set` 지시문을 사용하여 메서드를 호출하고 변수를 무시하는 것이 이 문제를 해결하는 방법이 되기도 합니다. 예제:

```
#set ($myMap = {})
#set($discard = $myMap.put("id", "first value"))
```

예상치 못한 문자열이 템플릿에 인쇄되지 않도록 하므로 템플릿에서이 기술을 사용할 수 있습니다. AWS AppSync는 더 간결한 표기법으로 동일한 동작을 제공하는 대체 편의 함수를 제공합니다. 이 함수를 사용하면 이러한 구현 세부 사항에 대해 개발자가 생각할 필요가 없습니다. `$util.quiet()` 또는 `$util.qr()` 별칭으로 이 함수에 액세스할 수 있습니다. 예제:

```
#set ($myMap = {})
#set ($myList = [])

##Nothing prints out
$util.quiet($myMap.put("id", "first value"))
##Nothing prints out
$util.qr($myList.add("something"))
```

## 문자열
<a name="strings"></a>

여러 프로그래밍 언어와 마찬가지로, 문자열을 다루기가 어려울 수 있으며, 특히 변수에서 문자열을 구성하려는 경우에는 더욱 더 그렇습니다. VTL과 함께 제공되는 공통된 사항이 있습니다.

DynamoDB 같은 데이터 소스에 데이터를 문자열로 삽입하려 하지만 이 문자열이 GraphQL 인수 같은 변수에서 채워진다고 가정해 보겠습니다. 문자열에는 큰따옴표가 있으며 문자열에서 변수를 참조하려면 `"${}"`만 있으면 됩니다(따라서 [자동 참조 표기](https://velocity.apache.org/engine/1.7/user-guide.html#quiet-reference-notation)에서는 `!`가 없습니다). 이 형태는 JavaScript의 템플릿 리터럴과 비슷합니다([https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template\$1literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)).

```
#set($firstname = "Jeff")
$!{myMap.put("Firstname", "${firstname}")}
```

`"id" : { "S" : "$util.autoId()"}`와 같은 자동 ID를 생성하려 할 때 또는 GraphQL 클라이언트에서 인수를 사용할 때 `"author": { "S" : "${context.arguments.author}"}`처럼 DynamoDB 요청 템플릿에서 이 형태를 볼 수 있습니다. 다시 말해서 문자열 내부에서 메서드의 결과나 변수를 참조하여 데이터를 채울 수 있다는 뜻입니다.

또한 하위 문자열을 추출하는 등 Java [String 클래스](https://docs.oracle.com/javase/6/docs/api/java/lang/String.html)의 퍼블릭 메서드를 사용할 수도 있습니다.

```
#set($bigstring = "This is a long string, I want to pull out everything after the comma")
#set ($comma = $bigstring.indexOf(','))
#set ($comma = $comma +2)
#set ($substring = $bigstring.substring($comma))

$util.qr($myMap.put("substring", "${substring}"))
```

문자열 연결도 매우 일반적인 작업입니다. 변수 참조만을 사용하여 또는 정적 값과 함께 이 작업을 수행할 수 있습니다.

```
#set($s1 = "Hello")
#set($s2 = " World")

$util.qr($myMap.put("concat","$s1$s2"))
$util.qr($myMap.put("concat2","Second $s1 World"))
```

## Loops
<a name="loops"></a>

이제 변수를 생성하고 메서드를 호출했으므로 몇 가지 로직을 코드에 추가할 수 있습니다. 다른 언어와는 달리, VTL에서는 루프만 허용됩니다. 루프에서 반복 횟수는 미리 지정되어 있습니다. Velocity에는 `do..while`이 없습니다. 이 설계는 평가 프로세스가 항상 종료되도록 하고 GraphQL 작업 실행 시 확장성 범위를 제공합니다.

루프는 `#foreach`와 함께 생성되며 **루프 변수**와 **반복 가능한 객체**(예: 배열, 목록, 맵 또는 모음)를 제공해야 합니다. `#foreach` 루프와 관련된 클래식 프로그래밍 예제는 모음에서 항목을 반복하고 출력하는 것이므로, 여기서는 이러한 항목을 추출하여 맵에 추가합니다.

```
#set($start = 0)
#set($end = 5)
#set($range = [$start..$end])

#foreach($i in $range)
   ##$util.qr($myMap.put($i, "abc"))
   ##$util.qr($myMap.put($i, $i.toString()+"foo")) ##Concat variable with string
   $util.qr($myMap.put($i, "${i}foo"))     ##Reference a variable in a string with "${varname}"
#end
```

이 예제는 몇 가지 사항을 보여줍니다. 첫 번째는 범위 `[..]` 연산자와 함께 변수를 사용하여 반복 가능한 객체를 생성합니다. 그러고 각 항목이 작업에 사용할 수 있는 변수 `$i`에 의해 참조됩니다. 이전 예제에서는 2파운드 `##`으로 표시된 **주석**도 볼 수 있습니다. 또한 이 예제는 키 또는 값의 루프 변수 사용과 문자열을 사용한 다양한 연결 방법도 보여줍니다.

`$i`는 정수이므로 `.toString()` 메서드를 직접적으로 호출할 수 있습니다. GraphQL INT 유형의 경우 이 메서드가 유용할 수 있습니다.

또한 범위 연산자를 직접 사용할 수도 있습니다. 예를 들면 다음과 같습니다.

```
#foreach($item in [1..5])
    ...
#end
```

## 배열
<a name="arrays"></a>

지금까지는 맵을 잘 조작해 왔지만, VTL에서는 배열도 일반적으로 사용합니다. 아래와 같이 배열을 사용하여 `.isEmpty()`, `.size()`, `.set()`, `.get()` 및 `.add()` 같은 기본 메서드에 액세스할 수도 있습니다.

```
#set($array = [])
#set($idx = 0)

##adding elements
$util.qr($array.add("element in array"))
$util.qr($myMap.put("array", $array[$idx]))

##initialize array vals on create
#set($arr2 = [42, "a string", 21, "test"])

$util.qr($myMap.put("arr2", $arr2[$idx]))
$util.qr($myMap.put("isEmpty", $array.isEmpty()))  ##isEmpty == false
$util.qr($myMap.put("size", $array.size()))

##Get and set items in an array
$util.qr($myMap.put("set", $array.set(0, 'changing array value')))
$util.qr($myMap.put("get", $array.get(0)))
```

이전 예에서는 배열 인덱스 표기를 사용하여 `arr2[$idx]`가 있는 요소를 검색했습니다. 비슷한 방법으로 맵/딕셔너리에서 이름별로 조회할 수 있습니다.

```
#set($result = {
    "Author" : "Nadia",
    "Topic" : "GraphQL"
})

$util.qr($myMap.put("Author", $result["Author"]))
```

이 방법은 조건 사용 시 응답 템플릿의 데이터 원본에서 가져오는 결과를 필터링할 때 매우 일반적으로 사용합니다.

## 조건부 확인
<a name="conditional-checks"></a>

`#foreach`에 관한 이전 단원에서는 VTL에서 로직을 사용하여 데이터를 변환하는 몇 가지 예를 살펴보았습니다. 또한 실행 시간에 조건부 확인을 적용하여 데이터를 평가할 수 있습니다.

```
#if(!$array.isEmpty())
    $util.qr($myMap.put("ifCheck", "Array not empty"))
#else
    $util.qr($myMap.put("ifCheck", "Your array is empty"))
#end
```

부울 표현식에 대한 위의 `#if()` 점검은 잘 작동하지만, 연산자와 `#elseif()`를 사용하여 분기시킬 수도 있습니다.

```
#if ($arr2.size() == 0)
    $util.qr($myMap.put("elseIfCheck", "You forgot to put anything into this array!"))
#elseif ($arr2.size() == 1)
    $util.qr($myMap.put("elseIfCheck", "Good start but please add more stuff"))
#else
    $util.qr($myMap.put("elseIfCheck", "Good job!"))
#end
```

이 두 가지 예제에는 부정(\$1) 및 같음(==)이 나와 있습니다. 또한 \$1\$1, &&, >, <, >=, <= 및 \$1=을 사용할 수 있습니다.

```
#set($T = true)
#set($F = false)

#if ($T || $F)
  $util.qr($myMap.put("OR", "TRUE"))
#end

#if ($T && $F)
  $util.qr($myMap.put("AND", "TRUE"))
#end
```

 **참고:** `Boolean.FALSE` 및 `null`만 조건문에서 false로 간주됩니다. 제로(0)와 빈 문자열("")은 false로 간주되지 않습니다.

## 연산자
<a name="operators"></a>

작업자가 연산자 없이 산술 작업을 수행할 수 있는 완벽한 프로그래밍 언어는 없습니다. 다음은 시작하는 데 도움이 될 몇 가지 예제입니다.

```
#set($x = 5)
#set($y = 7)
#set($z = $x + $y)
#set($x-y = $x - $y)
#set($xy = $x * $y)
#set($xDIVy = $x / $y)
#set($xMODy = $x % $y)

$util.qr($myMap.put("z", $z))
$util.qr($myMap.put("x-y", $x-y))
$util.qr($myMap.put("x*y", $xy))
$util.qr($myMap.put("x/y", $xDIVy))
$util.qr($myMap.put("x|y", $xMODy))
```

### 루프와 조건부 함께 사용
<a name="loops-and-conditionals-together"></a>

데이터 원본 쓰기 또는 읽기 등 VTL에서 데이터를 변환할 때는 객체를 루핑하고 나서 확인을 수행한 다음 작업을 수행하는 것이 일반적입니다. 이전 단원의 도구 중 일부를 결합하여 다양한 기능을 이용할 수 있습니다. 한 가지 유용한 점이라면, `#foreach`가 각 항목에 `.count`를 자동으로 제공한다는 사실입니다.

```
#foreach ($item in $arr2)
  #set($idx = "item" + $foreach.count)
  $util.qr($myMap.put($idx, $item))
#end
```

예를 들면 단순히 맵에서 특정 크기 이하인 값을 추출하고자 하는 경우가 있습니다. 이 개수 값에 조건문 및 `#break` 문을 사용하여 다음을 수행할 수 있습니다.

```
#set($hashmap = {
  "DynamoDB" : "https://aws.amazon.com/dynamodb/",
  "Amplify" : "https://github.com/aws/aws-amplify",
  "DynamoDB2" : "https://aws.amazon.com/dynamodb/",
  "Amplify2" : "https://github.com/aws/aws-amplify"
})

#foreach ($key in $hashmap.keySet())
    #if($foreach.count > 2)
    #break
  #end
    $util.qr($myMap.put($key, $hashmap.get($key)))
#end
```

이전 `#foreach`는 `.keySet()`를 사용하여 반복되는 데, 이것을 맵에서 사용할 수 있습니다. 이렇게 하면 `$key`를 가져와서 `.get($key)`를 사용하여 값을 참조할 수 있는 액세스 권한이 부여됩니다. AWS AppSync에서 클라이언트의 GraphQL 인수는 맵으로 저장됩니다. 이러한 인수는 `.entrySet()`을 통해 반복할 수 있으며, 이러한 반복을 통해 키와 값 모두에 한 번에 액세스하고, 입력 변환이나 확인 등 복잡한 조건부 검증을 수행하거나 다른 변수를 채울 수 있습니다.

```
#foreach( $entry in $context.arguments.entrySet() )
#if ($entry.key == "XYZ" && $entry.value == "BAD")
    #set($myvar = "...")
  #else
    #break
  #end
#end
```

다른 일반적인 예제에서는 데이터 동기화 시 초기 객체 버전(충돌 해결 시 매우 중요) 또는 권한 부여 확인을 위한 객체의 기본 소유자(이 블록 게시물을 생성한 Mary) 같은 기본 정보가 자동으로 채워지므로, 다음과 같습니다.

```
#set($myMap.owner ="Mary")
#set($myMap.defaultOwners = ["Admins", "Editors"])
```

## 컨텍스트
<a name="context"></a>

VTL을 사용하여 AWS AppSync 해석기에서 로직 점검을 수행하는 데 익숙해지셨을 테니, 지금부터는 컨텍스트 객체를 살펴보겠습니다.

```
$util.qr($myMap.put("context", $context))
```

여기에는 GraphQL 요청에서 액세스할 수 있는 모든 정보가 들어 있습니다. 자세한 설명은 [컨텍스트 참조](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)를 참조하십시오.

## 필터링
<a name="filtering"></a>

지금까지 이 자습서에서는 매우 단순한 JSON 변환을 사용하여 Lambda 함수의 모든 정보가 GraphQL 쿼리로 반환되었습니다.

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

VTL 로직은 데이터 원본에서 응답을 가져올 때, 특히 리소스에 대한 권한 부여 확인을 수행할 때 매우 유용합니다. 몇 가지 예를 살펴보겠습니다. 먼저 다음과 같이 응답 템플릿을 변경해 보겠습니다.

```
#set($data = {
    "id" : "456",
    "meta" : "Valid Response"
})

$util.toJson($data)
```

GraphQL 작업에서 어떤 일이 일어나든, 하드코딩된 값이 클라이언트로 반환됩니다. 이 자습서의 앞부분에서 조건문에 대해 알아볼 때 `meta` 값에서 설정했던 Lambda 응답으로 `elseIfCheck` 필드가 채워지도록 이 코드를 조금 변경합니다.

```
#set($data = {
    "id" : "456"
})

#foreach($item in $context.result.entrySet())
    #if($item.key == "elseIfCheck")
        $util.qr($data.put("meta", $item.value))
    #end
#end

$util.toJson($data)
```

 `$context.result`는 맵이므로 `entrySet()`을 사용하여 반환된 키나 값에 대해 로직을 수행할 수 있습니다. `$context.identity`에는 GraphQL 작업을 수행한 사용자에 대한 정보가 포함되어 있으므로, 데이터 원본에서 권한 부여 정보를 반환할 때 로직에 근거하여 사용자에게 데이터 전체 또는 일부를 반환하거나 데이터를 반환하지 않을 수 있습니다. 응답 템플릿을 다음과 같은 형태로 변경합니다.

```
#if($context.result["id"] == 123)
    $util.toJson($context.result)
  #else
    $util.unauthorized()
#end
```

GraphQL 쿼리를 실행할 경우 데이터가 보통 때처럼 반환됩니다. 하지만 ID 인수를 123(`query test { get(id:456 meta:"badrequest"){} }`) 이외의 것으로 변경할 경우 권한 부여 실패 메시지가 표시됩니다.

[권한 부여 사용 사례](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases) 단원에서 권한 부여 시나리오의 다른 예를 확인할 수 있습니다.

### 템플릿 샘플
<a name="appendix-template-sample"></a>

자습서를 따라 진행했다면 단계별로 이 템플릿을 빌드했을 것입니다. 그렇지 않은 경우, 테스트를 위해 복사할 수 있는 템플릿이 아래에 포함되어 있습니다.

 **요청 템플릿** 

```
#set( $myMap = {
  "id": $context.arguments.id,
  "meta": "stuff",
  "upperMeta" : "$context.arguments.meta.toUpperCase()"
} )

##This is how you would do it in two steps with a "quiet reference" and you can use it for invoking methods, such as .put() to add items to a Map
#set ($myMap2 = {})
$util.qr($myMap2.put("id", "first value"))

## Properties are created with a dot notation
#set($myMap.myProperty = "ABC")
#set($myMap.arrProperty = ["Write", "Some", "GraphQL"])
#set($myMap.jsonProperty = {
    "AppSync" : "Offline and Realtime",
    "Cognito" : "AuthN and AuthZ"
})

##When you are inside a string and just have ${} without ! it means stuff inside curly braces are a reference
#set($firstname = "Jeff")
$util.qr($myMap.put("Firstname", "${firstname}"))

#set($bigstring = "This is a long string, I want to pull out everything after the comma")
#set ($comma = $bigstring.indexOf(','))
#set ($comma = $comma +2)
#set ($substring = $bigstring.substring($comma))
$util.qr($myMap.put("substring", "${substring}"))

##Classic for-each loop over N items:
#set($start = 0)
#set($end = 5)
#set($range = [$start..$end])
#foreach($i in $range)          ##Can also use range operator directly like #foreach($item in [1...5])
   ##$util.qr($myMap.put($i, "abc"))
   ##$util.qr($myMap.put($i, $i.toString()+"foo")) ##Concat variable with string
   $util.qr($myMap.put($i, "${i}foo"))     ##Reference a variable in a string with "${varname)"
#end

##Operators don't work
#set($x = 5)
#set($y = 7)
#set($z = $x + $y)
#set($x-y = $x - $y)
#set($xy = $x * $y)
#set($xDIVy = $x / $y)
#set($xMODy = $x % $y)
$util.qr($myMap.put("z", $z))
$util.qr($myMap.put("x-y", $x-y))
$util.qr($myMap.put("x*y", $xy))
$util.qr($myMap.put("x/y", $xDIVy))
$util.qr($myMap.put("x|y", $xMODy))

##arrays
#set($array = ["first"])
#set($idx = 0)
$util.qr($myMap.put("array", $array[$idx]))
##initialize array vals on create
#set($arr2 = [42, "a string", 21, "test"])
$util.qr($myMap.put("arr2", $arr2[$idx]))
$util.qr($myMap.put("isEmpty", $array.isEmpty()))  ##Returns false
$util.qr($myMap.put("size", $array.size()))
##Get and set items in an array
$util.qr($myMap.put("set", $array.set(0, 'changing array value')))
$util.qr($myMap.put("get", $array.get(0)))

##Lookup by name from a Map/dictionary in a similar way:
#set($result = {
    "Author" : "Nadia",
    "Topic" : "GraphQL"
})
$util.qr($myMap.put("Author", $result["Author"]))


##Conditional examples
#if(!$array.isEmpty())
$util.qr($myMap.put("ifCheck", "Array not empty"))
#else
$util.qr($myMap.put("ifCheck", "Your array is empty"))
#end

#if ($arr2.size() == 0)
$util.qr($myMap.put("elseIfCheck", "You forgot to put anything into this array!"))
#elseif ($arr2.size() == 1)
$util.qr($myMap.put("elseIfCheck", "Good start but please add more stuff"))
#else
$util.qr($myMap.put("elseIfCheck", "Good job!"))
#end

##Above showed negation(!) and equality (==), we can also use OR, AND, >, <, >=, <=, and !=
#set($T = true)
#set($F = false)
#if ($T || $F)
  $util.qr($myMap.put("OR", "TRUE"))
#end

#if ($T && $F)
  $util.qr($myMap.put("AND", "TRUE"))
#end

##Using the foreach loop counter - $foreach.count
#foreach ($item in $arr2)
  #set($idx = "item" + $foreach.count)
  $util.qr($myMap.put($idx, $item))
#end

##Using a Map and plucking out keys/vals
#set($hashmap = {
    "DynamoDB" : "https://aws.amazon.com/dynamodb/",
    "Amplify" : "https://github.com/aws/aws-amplify",
    "DynamoDB2" : "https://aws.amazon.com/dynamodb/",
    "Amplify2" : "https://github.com/aws/aws-amplify"
})

#foreach ($key in $hashmap.keySet())
    #if($foreach.count > 2)
        #break
    #end
    $util.qr($myMap.put($key, $hashmap.get($key)))
#end

##concatenate strings
#set($s1 = "Hello")
#set($s2 = " World")
$util.qr($myMap.put("concat","$s1$s2"))
$util.qr($myMap.put("concat2","Second $s1 World"))

$util.qr($myMap.put("context", $context))

{
    "version" : "2017-02-28",
    "operation": "Invoke",
    "payload": $util.toJson($myMap)
}
```

 **응답 템플릿** 

```
#set($data = {
"id" : "456"
})
#foreach($item in $context.result.entrySet())   ##$context.result is a MAP so we use entrySet()
    #if($item.key == "ifCheck")
        $util.qr($data.put("meta", "$item.value"))
    #end
#end

##Uncomment this out if you want to test and remove the below #if check
##$util.toJson($data)

#if($context.result["id"] == 123)
    $util.toJson($context.result)
  #else
    $util.unauthorized()
#end
```