

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# での Aurora Serverless v2 の使用 AWS AppSync
<a name="tutorial-rds-resolvers"></a>

を使用して GraphQL API を Aurora Serverless データベースに接続します AWS AppSync。この統合により、GraphQL クエリ、ミューテーション、サブスクリプションを通じて SQL ステートメントを実行できます。これにより、リレーショナルデータを柔軟に操作できます。

**注記**  
このチュートリアルでは、`US-EAST-1` リージョンを使用しています。

**利点**
+ GraphQL とリレーショナルデータベースのシームレスな統合
+ GraphQL インターフェイスを使用して SQL オペレーションを実行する機能
+ Aurora Serverless v2 によるサーバーレスのスケーラビリティ
+  AWS Secrets Manager によるデータアクセスの保護
+ 入力のサニタイズによる SQL インジェクションに対する保護
+ フィルタリングや範囲操作などの柔軟なクエリ機能

**一般的なユースケース**
+ リレーショナルデータ要件を使用したスケーラブルなアプリケーションの構築
+ GraphQL の柔軟性と SQL データベース機能の両方を必要とする API の作成
+ GraphQL ミューテーションとクエリによるデータオペレーションの管理
+ セキュアなデータベースアクセスパターンの実装

このチュートリアルでは、以下について説明します。
+ Aurora Serverless v2 クラスターを設定する
+ Data API 機能を有効にする
+ データベース構造の作成と設定
+ データベースオペレーションの GraphQL スキーマを定義する
+ クエリとミューテーションのリゾルバーを実装する
+ 適切な入力サニタイズによりデータアクセスを保護する
+ GraphQL インターフェイスを使用してさまざまなデータベースオペレーションを実行する

**Topics**
+ [データベースクラスターを設定する](#create-cluster)
+ [Data API を有効にする](#enable-data-api)
+ [データベースとテーブルを作成する](#create-database-and-table)
+ [GraphQL スキーマ](#graphql-schema)
+ [API をデータベースオペレーションに接続する](#configuring-resolvers)
+ [API を使用してデータを変更する](#run-mutations)
+ [データを取得する](#run-queries)
+ [セキュアなデータアクセス](#input-sanitization)

## データベースクラスターを設定する
<a name="create-cluster"></a>

Amazon RDS データソースを に追加する前に AWS AppSync、まず Aurora Serverless v2 クラスターで Data API を有効にし**、 を使用してシークレットを設定**する必要があります*AWS Secrets Manager*。 AWS CLIを使用して Aurora Serverless v2 クラスターを作成することができます。

```
aws rds create-db-cluster \
    --db-cluster-identifier appsync-tutorial \
    --engine aurora-mysql \
    --engine-version 8.0 \
    --serverless-v2-scaling-configuration MinCapacity=0,MaxCapacity=1 \
    --master-username USERNAME \
    --master-user-password COMPLEX_PASSWORD \
    --enable-http-endpoint
```

これにより、クラスターの ARN が返されます。

クラスターを作成したら、次のコマンドを使用して Aurora Serverless v2 インスタンスを追加する必要があります。

```
aws rds create-db-instance \
    --db-cluster-identifier appsync-tutorial \
    --db-instance-identifier appsync-tutorial-instance-1 \
    --db-instance-class db.serverless \
    --engine aurora-mysql
```

**注記**  
これらのエンドポイントのアクティブ化には時間がかかります。ステータスは、クラスターの **[接続とセキュリティ]** タブの Amazon RDS コンソールで確認できます。次の AWS CLI コマンドを使用して、クラスターのステータスを確認することもできます。  

```
aws rds describe-db-clusters \
    --db-cluster-identifier appsync-tutorial \
    --query "DBClusters[0].Status"
```

 AWS Secrets Manager コンソールまたは AWS CLI を使用してシー*クレット*を作成し、前のステップ`COMPLEX_PASSWORD`の `USERNAME`と を使用して次のような入力ファイルを作成できます。

```
{
    "username": "USERNAME",
    "password": "COMPLEX_PASSWORD"
}
```

これをパラメータとして に渡します AWS CLI。

```
aws secretsmanager create-secret --name HttpRDSSecret --secret-string file://creds.json --region us-east-1
```

これにより、シークレットの ARN が返されます。

 Aurora Serverless クラスターとシークレットの **ARN をメモ**しておいてください。これらの ARN は後でデータソースを作成するときに AppSync コンソールで使用します。

## Data API を有効にする
<a name="enable-data-api"></a>

[RDS のドキュメントの指示に従う](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html)ことで、クラスターで Data API を有効にできます。Data API は AppSync データソースとして追加する前に有効にする必要があります。

## データベースとテーブルを作成する
<a name="create-database-and-table"></a>

Data API を有効にしたら、 AWS CLIの `aws rds-data execute-statement` コマンドで使用できるようになります。これにより、Aurora Serverless クラスターが正しく設定されていることを AppSync API への追加前に確認できます。まず、`--sql` のようなパラメータで *TESTDB* というデータベースを作成します。

```
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \
--schema "mysql"  --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1"  \
--region us-east-1 --sql "create DATABASE TESTDB"
```

これがエラーなしで実行されたら、*create table* コマンドを使用してテーブルを追加します。

```
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \
 --schema "mysql"  --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \
 --region us-east-1 \
 --sql "create table Pets(id varchar(200), type varchar(200), price float)" --database "TESTDB"
```

すべてが問題なく実行されたら、AppSync API のデータソースとしてクラスターを追加する手順に進むことができます。

## GraphQL スキーマ
<a name="graphql-schema"></a>

Aurora Serverless Data API がテーブルで起動されて実行中になったところで、次は GraphQL スキーマを作成し、ミューテーションとサブスクリプションを実行するためのリゾルバーをアタッチします。 AWS AppSync コンソールで新しい API を作成し、**スキーマ**ページに移動して、次のように入力します。

```
type Mutation {
    createPet(input: CreatePetInput!): Pet
    updatePet(input: UpdatePetInput!): Pet
    deletePet(input: DeletePetInput!): Pet
}

input CreatePetInput {
    type: PetType
    price: Float!
}

input UpdatePetInput {
id: ID!
    type: PetType
    price: Float!
}

input DeletePetInput {
    id: ID!
}

type Pet {
    id: ID!
    type: PetType
    price: Float
}

enum PetType {
    dog
    cat
    fish
    bird
    gecko
}

type Query {
    getPet(id: ID!): Pet
    listPets: [Pet]
    listPetsByPriceRange(min: Float, max: Float): [Pet]
}

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

 スキーマを**保存**し、[**データソース**] ページに移動して、新しいデータソースを作成します。データソースタイプとして [**Relational database (リレーショナルデータベース)**] を選択し、データソース名としてわかりやすい名前を入力します。前回の手順で作成したデータベースの名前と、そのデータベースを作成したクラスターの**クラスター ARN** を使用します。[**Role (ロール)**] では、AppSync により新しいロールを作成するか、以下のようなポリシーによりロールを作成できます。

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds-data:BatchExecuteStatement",
                "rds-data:BeginTransaction",
                "rds-data:CommitTransaction",
                "rds-data:ExecuteStatement",
                "rds-data:RollbackTransaction"
            ],
            "Resource": [
                "arn:aws:rds:us-east-1:111122223333:cluster:mydbcluster",
                "arn:aws:rds:us-east-1:111122223333:cluster:mydbcluster:*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Resource": [
            "arn:aws:secretsmanager:us-east-1:111122223333:secret:mysecret",
            "arn:aws:secretsmanager:us-east-1:111122223333:secret:mysecret:*"
            ]
        }
    ]
}
```

------

このポリシーには、ロールにアクセス許可を付与する 2 つの**ステートメント**があります。最初の**リソース**は Aurora Serverless クラスターで、2 番目のリソースは AWS Secrets Manager ARN です。**作成**をクリックする前に AppSync データソース構成内の**両方**の ARN を指定する必要があります。

これをパラメータとして に渡します AWS CLI。

```
aws secretsmanager create-secret \
  --name HttpRDSSecret \
  --secret-string file://creds.json \
  --region us-east-1
```

これにより、シークレットの ARN が返されます。 AWS AppSync コンソールでデータソースを作成するときは、Aurora Serverless クラスターの ARN と、後で のシークレットを書き留めます。

### データベース構造を構築する
<a name="create-database-and-table"></a>

Data API を有効にしたら、 AWS CLIの `aws rds-data execute-statement` コマンドで使用できるようになります。これにより、API に追加する前に Aurora Serverless v2 クラスターが正しく設定されます AWS AppSync 。まず、次のように `--sql` パラメータを使用して *TESTDB* というデータベースを作成します。

```
aws rds-data execute-statement \
                --resource-arn "arn:aws:rds:us-east-1:111122223333:cluster:appsync-tutorial" \
                --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333:secret:appsync-tutorial-rds-secret"  \
                --region us-east-1 \
                --sql "create DATABASE TESTDB"
```

これがエラーなしで実行されたら、次の *create table* コマンドを使用してテーブルを追加します。

```
aws rds-data execute-statement \
      --resource-arn "arn:aws:rds:us-east-1:111122223333:cluster:http-endpoint-test" \
      --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333:secret:testHttp2-AmNvc1" \
      --region us-east-1 \
      --sql "create table Pets(id varchar(200), type varchar(200), price float)" \
      --database "TESTDB"
```

### API インターフェイスを設計する
<a name="graphql-schema"></a>

Aurora Serverless v2 Data API がテーブルを使用して実行中になった後、GraphQL スキーマを作成し、ミューテーションとサブスクリプションを実行するためのリゾルバーをアタッチします。 AWS AppSync コンソールで新しい API を作成し、コンソールの**スキーマ**ページに移動して、次のように入力します。

```
type Mutation {
        createPet(input: CreatePetInput!): Pet
        updatePet(input: UpdatePetInput!): Pet
        deletePet(input: DeletePetInput!): Pet
    }
    
    input CreatePetInput {
        type: PetType
        price: Float!
    }
    
    input UpdatePetInput {
        id: ID!
        type: PetType
        price: Float!
    }
    
    input DeletePetInput {
        id: ID!
    }
    
    type Pet {
        id: ID!
        type: PetType
        price: Float
    }
    
    enum PetType {
        dog
        cat
        fish
        bird
        gecko
    }
    
    type Query {
        getPet(id: ID!): Pet
        listPets: [Pet]
        listPetsByPriceRange(min: Float, max: Float): [Pet]
    }
    
    schema {
        query: Query
        mutation: Mutation
    }
```

 スキーマを**保存**し、[**データソース**] ページに移動して、新しいデータソースを作成します。**[データソース]** タイプとして **[リレーショナルデータベース]** を選択し、わかりやすい名前を入力します。前回の手順で作成したデータベースの名前と、そのデータベースを作成したクラスターの**クラスター ARN** を使用します。**ロール**の場合、 に AWS AppSync 新しいロールを作成するか、次のようなポリシーで作成させることができます。

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

****  

```
{
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "rds-data:BatchExecuteStatement",
                    "rds-data:BeginTransaction",
                    "rds-data:CommitTransaction",
                    "rds-data:ExecuteStatement",
                    "rds-data:RollbackTransaction"
                ],
                "Resource": [
                    "arn:aws:rds:us-east-1:111122223333:cluster:mydbcluster",
                    "arn:aws:rds:us-east-1:111122223333:cluster:mydbcluster:*"
                ]
            },
            {
                "Effect": "Allow",
                "Action": [
                    "secretsmanager:GetSecretValue"
                ],
                "Resource": [
                "arn:aws:secretsmanager:us-east-1:111122223333:secret:mysecret",
                "arn:aws:secretsmanager:us-east-1:111122223333:secret:mysecret:*"
                ]
            }
        ]
    }
```

------

このポリシーには、ロールにアクセス許可を付与する 2 つの**ステートメント**があります。最初の**リソース**は Aurora Serverless v2 クラスターで、2 つ目は AWS Secrets Manager ARN です。Create をクリックする前に、 AWS AppSync データソース設定で**両方の** ARNs ****を指定する必要があります。

## API をデータベースオペレーションに接続する
<a name="configuring-resolvers"></a>

有効な GraphQL スキーマと RDS データソースを用意できたところで、リゾルバーをスキーマへの GraphQL フィールドにアタッチできます。この API は以下の機能を提供します。

1. *Mutation.createPet* フィールドを使用してペットを作成する

1. *Mutation.updatePet* フィールドを使用してペットを更新する

1. *Mutation.deletePet* フィールドを使用してペットを削除する

1. *Query.getPet* フィールドを使用して 1 つのペットを取得する

1. *Query.listPets* フィールドを使用してすべてのペットを一覧表示する

1. *Query.listPetsByPriceRange* フィールドを使用してペットを価格帯別に一覧表示する

### Mutation.createPet
<a name="mutation-createpet"></a>

 AWS AppSync コンソールのスキーマエディタから、右側の「 **のリゾルバーをア**タッチする」を選択します`createPet(input: CreatePetInput!): Pet`。[RDS データソース] を選択します。**[リクエストマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
#set($id=$utils.autoId())
{
"version": "2018-05-29",
    "statements": [
        "insert into Pets VALUES (:ID, :TYPE, :PRICE)",
        "select * from Pets WHERE id = :ID"
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id",
        ":TYPE": $util.toJson($ctx.args.input.type),
        ":PRICE": $util.toJson($ctx.args.input.price)
    }
}
```

SQL ステートメントは、**statements** 配列内での順序に基づいて順番に実行されます。結果はその同じ順序で返されます。これはミューテーションなので、*挿入*の後に*選択*ステートメントを実行して、GraphQL レスポンスマッピングテンプレートに入力するための、コミットされた値を取得します。

**[レスポンスマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
```

*ステートメント*には 2 つの SQL クエリがあるため、データベースから返される行列の 2 番目の結果を `$utils.rds.toJsonString($ctx.result))[1][0])` で指定する必要があります。

### Mutation.updatePet
<a name="mutation-updatepet"></a>

 AWS AppSync コンソールのスキーマエディタから、 の**リゾルバーをア**タッチを選択します`updatePet(input: UpdatePetInput!): Pet`。**[RDS データソース]** を選択します。**[リクエストマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
{
"version": "2018-05-29",
    "statements": [
        $util.toJson("update Pets set type=:TYPE, price=:PRICE WHERE id=:ID"),
        $util.toJson("select * from Pets WHERE id = :ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id",
        ":TYPE": $util.toJson($ctx.args.input.type),
        ":PRICE": $util.toJson($ctx.args.input.price)
    }
}
```

**[レスポンスマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
```

### Mutation.deletePet
<a name="mutation-deletepet"></a>

 AWS AppSync コンソールのスキーマエディタから、 の**リゾルバーをア**タッチを選択します`deletePet(input: DeletePetInput!): Pet`。**[RDS データソース]** を選択します。**[リクエストマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
{
"version": "2018-05-29",
    "statements": [
        $util.toJson("select * from Pets WHERE id=:ID"),
        $util.toJson("delete from Pets WHERE id=:ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id"
    }
}
```

**[レスポンスマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
```

### Query.getPet
<a name="query-getpet"></a>

スキーマに対してミューテーションが作成されたところで、3 つのクエリを接続して、個々の項目、リストを取得し、SQL フィルタを適用する方法を紹介します。 AWS AppSync コンソールの**スキーマエディタ**から、 の**リゾルバーをア**タッチを選択します`getPet(id: ID!): Pet`。**[RDS データソース]** を選択します。**[リクエストマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
{
"version": "2018-05-29",
        "statements": [
            $util.toJson("select * from Pets WHERE id=:ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.id"
    }
}
```

**[レスポンスマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
```

### Query.listPets
<a name="query-listpets"></a>

 AWS AppSync コンソールのスキーマエディタから、右側の「 **のリゾルバーをア**タッチする」を選択します`getPet(id: ID!): Pet`。**[RDS データソース]** を選択します。**[リクエストマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
{
    "version": "2018-05-29",
    "statements": [
        "select * from Pets"
    ]
}
```

**[レスポンスマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
```

### Query.listPetsByPriceRange
<a name="query-listpetsbypricerange"></a>

 AWS AppSync コンソールのスキーマエディタから、右側の「 **のリゾルバーをア**タッチする」を選択します`getPet(id: ID!): Pet`。**[RDS データソース]** を選択します。**[リクエストマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
{
    "version": "2018-05-29",
    "statements": [
            "select * from Pets where price > :MIN and price < :MAX"
    ],

    "variableMap": {
        ":MAX": $util.toJson($ctx.args.max),
        ":MIN": $util.toJson($ctx.args.min)
    }
}
```

**[レスポンスマッピングテンプレート]** セクションで、以下のテンプレートを追加します。

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
```

## API を使用してデータを変更する
<a name="run-mutations"></a>

すべてのリゾルバーを SQL ステートメントで設定し、GraphQL API を Serverless Aurora Data API に接続したところで、ミューテーションとクエリの実行を開始できます。 AWS AppSync コンソールで、**クエリ**タブを選択し、次のように入力してペットを作成します。

```
mutation add {
    createPet(input : { type:fish, price:10.0 }){
        id
        type
        price
    }
}
```

レスポンスには、*id*、*type*、*price* が含まれています。

```
{
  "data": {
    "createPet": {
      "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a",
      "type": "fish",
      "price": "10.0"
    }
  }
}
```

この項目は *updatePet* ミューテーションを実行することで変更できます。

```
mutation update {
    updatePet(input : {
        id: ID_PLACEHOLDER,
        type:bird,
        price:50.0
    }){
        id
        type
        price
    }
}
```

事前の*createPet*オペレーションから返された*id*を使用したことに注意してください。リゾルバーが `$util.autoId()` を利用したため、これがレコードに固有の値になります。同様の方法でレコードを削除できます。

```
mutation delete {
    deletePet(input : {id:ID_PLACEHOLDER}){
        id
        type
        price
    }
}
```

最初のミューテーションで *price* に異なる値を使用してレコードをいくつか作成したら、クエリをいくつか実行します。

## データを取得する
<a name="run-queries"></a>

引き続きコンソールの **[クエリ]** タブで、以下のステートメントを使用して、作成したすべてのレコードを一覧表示します。

```
query allpets {
    listPets {
        id
        type
        price
    }
}
```

次の GraphQL クエリを使用して、*Query.listPetsByPriceRange* のマッピングテンプレートに `where price > :MIN and price < :MAX` があった、SQL の *WHERE* 述語を活用します。

```
query petsByPriceRange {
    listPetsByPriceRange(min:1, max:11) {
        id
        type
        price
    }
}
```

*price* が 1 ドル以上、10 ドル未満のレコードのみが表示されます。最後に、以下のようにクエリを実行して個々のレコードを取得できます。

```
query onePet {
    getPet(id:ID_PLACEHOLDER){
        id
        type
        price
    }
}
```

## セキュアなデータアクセス
<a name="input-sanitization"></a>

SQL インジェクションは、データベースアプリケーションのセキュリティ脆弱性を利用して行われます。これは、攻撃者がユーザー入力フィールドを通じて悪意のある SQL コードを挿入した場合に発生します。これにより、データベースデータへの不正アクセスが可能になります。`variableMap` を使用して SQL インジェクション攻撃から保護する前に、すべてのユーザー入力を慎重に検証してサニタイズすることをお勧めします。変数マップを使用しない場合、GraphQL 操作の引数をサニタイズする責任があります。そのための 1 つの方法は、Data API に対して SQL ステートメントを実行する前に、リクエストマッピングテンプレートに入力固有の検証手順を提供することです。`listPetsByPriceRange` 例のリクエストマッピングテンプレートを変更する方法を見てみましょう。ユーザー入力だけに頼るのではなく、以下のことが可能です。

```
#set($validMaxPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.maxPrice))

#set($validMinPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.minPrice))


#if (!$validMaxPrice || !$validMinPrice)
    $util.error("Provided price input is not valid.")
#end
{
    "version": "2018-05-29",
    "statements": [
            "select * from Pets where price > :MIN and price < :MAX"
    ],

    "variableMap": {
        ":MAX": $util.toJson($ctx.args.maxPrice),
        ":MIN": $util.toJson($ctx.args.minPrice)
    }
}
```

Data API に対してリゾルバーを実行するときに不正な入力から保護するもう 1 つの方法は、プリペアードステートメントをストアドプロシージャおよびパラメータ化された入力と共に使用することです。例えば、`listPets` のリゾルバーで、*select* をプリペアードステートメントとして実行する以下のプロシージャを定義します。

```
CREATE PROCEDURE listPets (IN type_param VARCHAR(200))
  BEGIN
     PREPARE stmt FROM 'SELECT * FROM Pets where type=?';
     SET @type = type_param;
     EXECUTE stmt USING @type;
     DEALLOCATE PREPARE stmt;
  END
```

これは、Aurora Serverless v2 インスタンスで作成します。

```
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:xxxxxxxxxxxx:cluster:http-endpoint-test" \
--schema "mysql"  --secret-arn "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:httpendpoint-xxxxxx"  \
--region us-east-1  --database "DB_NAME" \
--sql "CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END"
```

その結果、listPets のリゾルバーコードは、ストアドプロシージャを呼び出すシンプルなものになりました。少なくとも、文字列入力では一重引用符を[エスケープ](#escaped)する必要があります。

```
#set ($validType = $util.isString($ctx.args.type) && !$util.isNullOrBlank($ctx.args.type))
#if (!$validType)
    $util.error("Input for 'type' is not valid.", "ValidationError")
#end

{
    "version": "2018-05-29",
    "statements": [
        "CALL listPets(:type)"
    ]
    "variableMap": {
        ":type": $util.toJson($ctx.args.type.replace("'", "''"))
    }
}
```

### エスケープ文字列の使用
<a name="escaped"></a>

`'some string value'` のように、一重引用符を使用して、SQL ステートメントの文字列リテラルの開始と終了を表します。1 つ以上の一重引用符 (`'`) を含む文字列値を文字列内で使用するには、それぞれを 2 つの一重引用符 (`''`) に置き換える必要があります。例えば、入力文字列が `Nadia's dog` の場合、SQL ステートメントでは次のようにエスケープします。

```
update Pets set type='Nadia''s dog' WHERE id='1'
```