

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Uso de Aurora Serverless v2 con AWS AppSync
<a name="tutorial-rds-resolvers"></a>

Connect su API GraphQL a las bases de datos Aurora Serverless mediante. AWS AppSync Esta integración le permite ejecutar instrucciones SQL a través de consultas, mutaciones y suscripciones de GraphQL, lo que le brinda una forma flexible de interactuar con sus datos relacionales.

**nota**  
En este tutorial se utiliza la región `US-EAST-1`.

**Ventajas**
+ Integración perfecta entre GraphQL y bases de datos relacionales
+ Capacidad para realizar operaciones SQL a través de interfaces de GraphQL
+ Escalabilidad sin servidor con Aurora Serverless v2
+ Acceso seguro a los datos a través de AWS Secrets Manager
+ Protección contra la inyección de código SQL mediante el saneamiento de entradas
+ Capacidades de consulta flexibles que incluyen operaciones de filtrado y rango

**Casos de uso común**
+ Creación de aplicaciones escalables con requisitos de datos relacionales
+ Crear APIs eso requiere flexibilidad de GraphQL y capacidades de bases de datos SQL
+ Administración de operaciones de datos mediante mutaciones y consultas de GraphQL
+ Implementación de patrones de acceso seguro a bases de datos

En este tutorial, aprenderá lo siguiente:
+ Configuración de un clúster de Aurora Serverless v2
+ Habilitación de la funcionalidad de la API de datos
+ Creación y configuración de estructuras de base de datos
+ Definición de esquemas de GraphQL para operaciones de bases de datos
+ Implementación de solucionadores para consultas y mutaciones
+ Protección del acceso a sus datos mediante el saneamiento adecuado de las entradas
+ Ejecución de varias operaciones de bases de datos a través de interfaces de GraphQL

**Topics**
+ [Configuración del clúster de base de datos](#create-cluster)
+ [Habilitar la API de datos](#enable-data-api)
+ [Creación de una base de datos y tabla](#create-database-and-table)
+ [Esquema de GraphQL](#graphql-schema)
+ [Conexión de su API a las operaciones de la base de datos](#configuring-resolvers)
+ [Modificación de los datos a través de la API](#run-mutations)
+ [Recuperación de los datos](#run-queries)
+ [Protección del acceso a los datos](#input-sanitization)

## Configuración del clúster de base de datos
<a name="create-cluster"></a>

Antes de añadir una fuente de datos de Amazon RDS AWS AppSync, primero debe habilitar una API de datos en un clúster de Aurora Serverless v2 y **configurar un secreto mediante**. *AWS Secrets Manager* Puede crear un clúster de Aurora Serverless v2 con la AWS CLI:

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

Esto devolverá un ARN para el clúster.

Tras crear el clúster, debe agregar una instancia de Aurora Serverless v2 mediante el siguiente comando.

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

**nota**  
Estos puntos de conexión tardan un tiempo en activarse. Puede comprobar su estado en la consola de Amazon RDS, en la pestaña **Conectividad y seguridad** del clúster. También puede comprobar el estado del clúster con el siguiente AWS CLI comando.   

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

Puede crear un *secreto* con la AWS Secrets Manager consola o AWS CLI con un archivo de entrada como el siguiente utilizando `USERNAME` y `COMPLEX_PASSWORD` desde el paso anterior.

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

Pasa esto como parámetro a AWS CLI:

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

Esto devolverá un ARN para el secreto.

 **Anote el ARN** del clúster Aurora Serverless y el secreto para usarlos posteriormente en la AppSync consola al crear una fuente de datos.

## Habilitar la API de datos
<a name="enable-data-api"></a>

Puede habilitar la API de datos en el clúster [siguiendo las instrucciones de la documentación de RDS](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html). La API de datos debe estar habilitada antes de añadirla como fuente de AppSync datos.

## Creación de una base de datos y tabla
<a name="create-database-and-table"></a>

Una vez que tenga habilitada su API de datos, puede asegurarse de que funciona con el comando `aws rds-data execute-statement` de la AWS CLI. Esto garantizará que el clúster Aurora Serverless esté configurado correctamente antes de añadirlo a la AppSync API. En primer lugar, cree una base de datos denominada *TESTDB* con el parámetro `--sql` del siguiente modo:

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

Si esto se ejecuta sin errores, añada una tabla con el comando de *creación de tablas*:

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

Si todo se ha ejecutado sin problemas, puede continuar y añadir el clúster como fuente de datos en su AppSync API.

## Esquema de GraphQL
<a name="graphql-schema"></a>

Ahora que su API de datos de Aurora Serverless está en marcha con una tabla, vamos a crear un esquema GraphQL y asociar los solucionadores para realizar mutaciones y suscripciones. Crea una nueva API en la AWS AppSync consola, ve a la página del **esquema** e introduce lo siguiente:

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

 **Guarde** su esquema y vaya a la página **Data Sources (Orígenes de datos)** y cree un nuevo origen de datos. Seleccione la **Relational database (Base de datos relacional)** para el tipo de origen de datos y proporcione un nombre fácil de recordar. Utilice el nombre de la base de datos que ha creado en el último paso, así como el **Cluster ARN (ARN del clúster)** en el que lo creó. Para el **rol**, puede AppSync crear un rol nuevo o uno con una política similar a la siguiente:

------
#### [ 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:*"
            ]
        }
    ]
}
```

------

Tenga en cuenta que hay dos **Statements (Instrucciones)** en esta política a las que está concediendo acceso de rol. El primer **recurso** es su clúster Aurora Serverless y el segundo es su AWS Secrets Manager ARN. **Deberá proporcionar **AMBOS** ARNs en la configuración de la fuente de AppSync datos antes de hacer clic en Crear.**

Pase esto como parámetro a AWS CLI.

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

Esto devolverá un ARN para el secreto. Al crear una fuente de datos en la consola, anote el ARN del clúster Aurora Serverless y el secreto para más adelante. AWS AppSync 

### Creación de la estructura de su base de datos
<a name="create-database-and-table"></a>

Una vez que tenga habilitada su API de datos, puede asegurarse de que funciona con el comando `aws rds-data execute-statement` de la AWS CLI. Esto garantizará que el clúster de Aurora Serverless v2 esté configurado correctamente antes de añadirlo a la AWS AppSync API. En primer lugar, cree una base de datos denominada *TESTDB* con el parámetro `--sql` del siguiente modo.

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

Si esto se ejecuta sin errores, añada una tabla con el siguiente comando de *creación de tablas*:

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

### Diseño de la interfaz de API
<a name="graphql-schema"></a>

Una vez que la API de datos de Aurora Serverless v2 está en marcha con una tabla, cree un esquema GraphQL y asocie los solucionadores para realizar mutaciones y suscripciones. Cree una nueva API en la AWS AppSync consola, vaya a la página del **esquema** de la consola e introduzca lo siguiente.

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

 **Guarde** su esquema y vaya a la página **Data Sources (Orígenes de datos)** y cree un nuevo origen de datos. Seleccione **Base de datos relacional** para el tipo de **origen de datos** y proporcione un nombre fácil de recordar. Utilice el nombre de la base de datos que ha creado en el último paso, así como el **Cluster ARN (ARN del clúster)** en el que lo creó. Para el **rol**, puede AWS AppSync crear un rol nuevo o uno con una política similar a la siguiente.

------
#### [ 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:*"
                ]
            }
        ]
    }
```

------

Tenga en cuenta que hay dos **Statements (Instrucciones)** en esta política a las que está concediendo acceso de rol. El primer **recurso** es su clúster Aurora Serverless v2 y el segundo es su AWS Secrets Manager ARN. **Deberá proporcionar **AMBOS** ARNs en la configuración de la fuente de AWS AppSync datos antes de hacer clic en Crear.**

## Conexión de su API a las operaciones de la base de datos
<a name="configuring-resolvers"></a>

Ahora que tenemos un esquema de GraphQL válido y un origen de datos de RDS, podemos asociar los solucionadores a los campos de GraphQL en el esquema. Nuestra API ofrecerá las siguientes capacidades:

1. crear una mascota con el campo *Mutation.createPet*

1. actualizar una mascota con el campo *Mutation.updatePet*

1. eliminar una mascota con el campo *Mutation.deletePet*

1. obtener una mascota única con el campo *Query.getPet*

1. enumerar todas las mascotas con el campo *Query.listPets*

1. publique las mascotas en un rango de precios mediante la *consulta. listPetsByPriceRange*campo

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

En el editor de esquemas de la AWS AppSync consola, en la parte derecha, selecciona **Attach Resolver** for`createPet(input: CreatePetInput!): Pet`. Elija el origen de los datos de RDS. En la sección **Plantilla de mapeo de solicitudes**, añada la siguiente plantilla:

```
#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)
    }
}
```

El sistema ejecuta las instrucciones SQL de forma secuencial, en función del orden de la matriz **instrucciones**. Los resultados volverán en el mismo orden. Dado que se trata de una mutación, ejecute una instrucción *seleccionar* después de *insertar* para recuperar los valores confirmados con objeto de rellenar la plantilla de mapeo de respuesta de GraphQL.

En la sección **Plantilla de mapeo de respuestas**, añada la siguiente plantilla:

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

Debido a que las *statements (instrucciones)* tienen dos consultas SQL, necesitamos especificar el segundo resultado en la matriz que viene de la base de datos con: `$utils.rds.toJsonString($ctx.result))[1][0])`.

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

En el editor de esquemas de la AWS AppSync consola, seleccione **Attach Resolver** for`updatePet(input: UpdatePetInput!): Pet`. Elija el **origen de los datos de RDS**. En la sección **Plantilla de mapeo de solicitudes**, añada la siguiente plantilla.

```
{
"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)
    }
}
```

En la sección **Plantilla de mapeo de respuestas**, añada la siguiente plantilla.

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

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

En el editor de esquemas de la AWS AppSync consola, elija **Attach Resolver** for`deletePet(input: DeletePetInput!): Pet`. Elija el **origen de los datos de RDS**. En la sección **Plantilla de mapeo de solicitudes**, añada la siguiente plantilla.

```
{
"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"
    }
}
```

En la sección **Plantilla de mapeo de respuestas**, añada la siguiente plantilla.

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

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

Ahora que se han creado las mutaciones para su esquema, conecte las tres consultas para mostrar cómo obtener elementos individuales, listas y aplicar el filtrado de SQL. En el **editor de esquemas** de la AWS AppSync consola, elija **Attach Resolver** for`getPet(id: ID!): Pet`. Elija el **origen de los datos de RDS**. En la sección **Plantilla de mapeo de solicitudes**, añada la siguiente plantilla.

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

En la sección **Plantilla de mapeo de respuestas**, añada la siguiente plantilla:

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

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

En el editor de esquemas de la AWS AppSync consola, en la parte derecha, selecciona **Attach Resolver** for`getPet(id: ID!): Pet`. Elija el **origen de los datos de RDS**. En la sección **Plantilla de mapeo de solicitudes**, añada la siguiente plantilla.

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

En la sección **Plantilla de mapeo de respuestas**, añada la siguiente plantilla.

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

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

En el editor de esquemas de la AWS AppSync consola, en el lado derecho, selecciona **Attach Resolver** for`getPet(id: ID!): Pet`. Elija el **origen de los datos de RDS**. En la sección **Plantilla de mapeo de solicitudes**, añada la siguiente plantilla.

```
{
    "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)
    }
}
```

En la sección **Plantilla de mapeo de respuestas**, añada la siguiente plantilla:

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

## Modificación de los datos a través de la API
<a name="run-mutations"></a>

Ahora que ha configurado todos sus solucionadores con instrucciones SQL y conectado API de GraphQL a su API de datos Aurora Serverless, puede comenzar a realizar mutaciones y consultas. En la AWS AppSync consola, selecciona la pestaña **Consultas** e introduce lo siguiente para crear una mascota:

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

La respuesta debe contener los valores de *id*, *type (tipo)* y *price (precio)* de la siguiente manera:

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

Puede modificar este elemento mediante la ejecución de la mutación *updatePet*:

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

Tenga en cuenta que hemos usado el *id* que ha devuelto la operación *createPet* anteriormente. Este será un valor único para su registro, ya que el solucionador obtuvo `$util.autoId()`. Podría eliminar un registro de un modo similar:

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

Cree un par de registros con la primera mutación con valores diferentes de *price (precio)* y, a continuación, ejecute algunas consultas.

## Recuperación de los datos
<a name="run-queries"></a>

En la pestaña **Consultas** de la consola, utilice la siguiente instrucción para obtener una lista de todos los registros que haya creado.

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

Aproveche el predicado *WHERE* de SQL que había `where price > :MIN and price < :MAX` en nuestra plantilla de mapeo para *Query. listPetsByPriceRange*con la siguiente consulta de GraphQL:

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

Solo debe ver registros con un *price (precio)* superior a 1 USD o inferior a 10 USD. Por último, puede realizar consultas para obtener registros individuales tal y como se indica a continuación:

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

## Protección del acceso a los datos
<a name="input-sanitization"></a>

La inyección de código SQL es una vulnerabilidad de seguridad en las aplicaciones de bases de datos. Se produce cuando los atacantes insertan código SQL malicioso a través de los campos de entrada del usuario. Esto puede permitir el acceso no autorizado a los datos de la base de datos. Recomendamos que valide y sanee meticulosamente todas las entradas de los usuarios antes de procesarlas con `variableMap` como protección contra los ataques de inyección de código SQL. Si no se utilizan mapas de variables, usted es el responsable de sanear los argumentos de sus operaciones de GraphQL. Una forma de hacerlo es proporcionando los pasos de validación específicos de entrada en la plantilla de mapeo de solicitudes antes de la ejecución de una instrucción SQL con respecto a la API de datos. Veamos cómo podemos modificar la plantilla de mapeo de solicitudes del ejemplo de `listPetsByPriceRange`. En lugar de confiar solamente en la entrada del usuario puede hacer lo siguiente:

```
#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)
    }
}
```

Otra forma de protegerse frente a la entrada no autorizada a la hora de ejecutar solucionadores con respecto a la API de datos es utilizar las instrucciones preparadas junto con el procedimiento almacenado y las entradas parametrizadas. Por ejemplo, en el solucionador para `listPets` defina el siguiente procedimiento que ejecuta *select (seleccionar)* como una instrucción preparada:

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

Cree esto en su instancia de 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"
```

El código de solucionador resultante para listPets se simplifica, ya que ahora simplemente llamamos al procedimiento almacenado: Como mínimo, toda entrada de cadena debe tener comillas simples [con caracteres de escape](#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("'", "''"))
    }
}
```

### Uso de cadenas de escape
<a name="escaped"></a>

Las comillas simples representan el inicio y el final de los literales de cadena en una instrucción SQL; por ejemplo, `'some string value'`. Para permitir el uso de valores de cadena con uno o más caracteres de comillas simples (`'`) dentro de una cadena, cada uno de ellos debe reemplazarse por dos comillas simples (`''`). Por ejemplo, si la cadena de entrada es `Nadia's dog`, para la instrucción SQL se aplicarían caracteres de escape de la siguiente forma:

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