Tutorial: Solucionadores de canalizaciones - AWS AppSync

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.

Tutorial: Solucionadores de canalizaciones

nota

Ahora admitimos de forma básica el tiempo de ejecución APPSYNC_JS y su documentación. Considere la opción de utilizar el tiempo de ejecución APPSYNC_JS y sus guías aquí.

AWS AppSync proporciona una manera sencilla de conectar un campo de GraphQL a un único origen de datos a través de los solucionadores de unidad. Sin embargo, ejecutar una sola operación podría no ser suficiente. Los solucionadores de canalización ofrecen la posibilidad de ejecutar operaciones en serie con respecto a los orígenes de datos. Cree funciones en su API y asócielas a un solucionador de canalización. Cada resultado de ejecución de la función se canaliza a la siguiente hasta que no quede ninguna función que ejecutar. Con los solucionadores de canalización, ahora puede crear flujos de trabajo más complejos directamente en AWS AppSync. En este tutorial, se crea una aplicación sencilla de visualización de imágenes, en la que los usuarios pueden publicar y ver imágenes publicadas por sus amigos.

Configuración en un clic

Si desea configurar automáticamente el punto de conexión de GraphQL en AWS AppSync con todos los solucionadores configurados y los recursos necesarios de AWS, puede utilizar la siguiente plantilla de AWS CloudFormation:

Esta pila crea los siguientes recursos en su cuenta:

  • Rol de IAM para que AWS AppSync obtenga acceso a los recursos de su cuenta

  • 2 tablas de DynamoDB

  • 1 grupo de usuarios de Amazon Cognito

  • 2 grupos de grupos de usuarios de Amazon Cognito

  • 3 usuarios de grupos de usuarios de Amazon Cognito

  • 1 API de AWS AppSync

Al final del proceso de creación de la pila de AWS CloudFormation, el usuario recibirá un mensaje de correo electrónico para cada uno de los tres usuarios de Amazon Cognito que se hayan creado. Cada correo electrónico contiene una contraseña temporal que se utiliza para iniciar sesión como un usuario de Amazon Cognito en la consola de AWS AppSync. Guarde las contraseñas para el resto del tutorial.

Configuración manual

Si prefiere ir manualmente a través de un proceso paso a paso por la consola de AWS AppSync, siga el proceso de configuración que se indica más abajo.

Configuración de los recursos que no son AWS AppSync

La API se comunica con dos tablas de DynamoDB: una tabla de imágenes que almacena imágenes y una tabla de amigos que almacena las relaciones entre los usuarios. La API está configurada para utilizar el grupo de usuarios de Amazon Cognito como el tipo de autenticación. La siguiente pila de AWS CloudFormation configura estos recursos en la cuenta.

Al final del proceso de creación de la pila de AWS CloudFormation, el usuario recibirá un mensaje de correo electrónico para cada uno de los tres usuarios de Amazon Cognito que se hayan creado. Cada correo electrónico contiene una contraseña temporal que se utiliza para iniciar sesión como un usuario de Amazon Cognito en la consola de AWS AppSync. Guarde las contraseñas para el resto del tutorial.

Creación de la API de GraphQL

Para crear la API de GraphQL en AWS AppSync:

  1. Abra la consola de AWS AppSync y elija Crear desde cero y Comenzar.

  2. Establezca como nombre de la API AppSyncTutorial-PicturesViewer.

  3. Seleccione Create (Crear).

La consola de AWS AppSync crea una nueva API de GraphQL automáticamente utilizando el modo de autenticación de clave de API. Puede utilizar la consola para configurar el resto de la API de GraphQL y ejecutar consultas en ella durante el resto de este tutorial.

Configuración de la API de GraphQL

Debe configurar la API de AWS AppSync con el grupo de usuarios de Amazon Cognito que acaba de crear.

  1. Elija la pestaña Settings.

  2. En la sección Authorization Type (Tipo de autorización), elija Amazon Cognito User Pool (Grupo de usuarios de Amazon Cognito).

  3. En Configuración del grupo de usuarios, elija US-WEST-2 para la Región de AWS.

  4. Elija el grupo de usuarios AppSyncTutorial-UserPool.

  5. Elija DENY (DENEGAR) como Default Action (Acción predeterminada).

  6. Deje el campo AppId client regex en blanco.

  7. Seleccione Save.

La API ahora está configurada para utilizar el grupo de usuarios de Amazon Cognito como el tipo de autenticación.

Configuración de orígenes de datos para las tablas de DynamoDB

Una vez creadas las tablas de DynamoDB, vaya a la API de GraphQL para AWS AppSync en la consola y elija la pestaña Orígenes de datos. Ahora, va a crear un origen de datos en AWS AppSync para cada una de las tablas de DynamoDB que acaba de crear.

  1. Elija la pestaña Data source (Origen de datos).

  2. Elija New (Nuevo) para crear un nuevo origen de datos.

  3. Escriba PicturesDynamoDBTable como nombre del origen de datos.

  4. En Tipo de origen de datos, elija Tabla de Amazon DynamoDB.

  5. Elija US-WEST-2 como región.

  6. En la lista de tablas, elija la tabla AppSyncTutorial-PicturesDynamoDB.

  7. En la sección Create or use an existing role (Crear o usar un rol existente), elija Existing role (Rol existente).

  8. Elija el rol que se acaba de crear desde la plantilla de CloudFormation. Si no ha cambiado ResourceNamePrefix, el nombre del rol debe ser AppSyncTutorial-DynamoDBRole.

  9. Seleccione Create (Crear).

Repita el mismo proceso para la tabla de amigos; el nombre de la tabla de DynamoDB debe ser AppSyncTutorial-Friends si no cambió el parámetro ResourceNamePrefix en el momento de crear la pila de CloudFormation.

Creación del esquema de GraphQL

Ahora que los orígenes de datos están conectados a las tablas de DynamoDB, vamos a crear un esquema de GraphQL. En el editor de esquemas de la consola de AWS AppSync, asegúrese de que su esquema coincida con el siguiente:

schema { query: Query mutation: Mutation } type Mutation { createPicture(input: CreatePictureInput!): Picture! @aws_auth(cognito_groups: ["Admins"]) createFriendship(id: ID!, target: ID!): Boolean @aws_auth(cognito_groups: ["Admins"]) } type Query { getPicturesByOwner(id: ID!): [Picture] @aws_auth(cognito_groups: ["Admins", "Viewers"]) } type Picture { id: ID! owner: ID! src: String } input CreatePictureInput { owner: ID! src: String! }

Elija Save Schema (Guardar esquema) para guardar el esquema.

Algunos de los campos de esquema se han comentado con la directiva @aws_auth. Dado que la API de configuración de acción predeterminada está establecida en DENY (DENEGAR), la API rechaza a todos los usuarios que no son miembros de los grupos mencionados dentro de la directiva @aws_auth. Para obtener más información acerca de cómo proteger la API, puede leer la página de seguridad. En este caso, solo los usuarios administradores tienen acceso a los campos Mutation.createPicture y Mutation.createFriendship mientras que los usuarios que son miembros de los grupos Admins (Administradores) o Viewers (Espectadores) pueden obtener acceso al campo Query.getPicturesByOwner. Todos los demás usuarios no tienen acceso.

Configuración de solucionadores

Ahora que tiene un esquema GraphQL válido y dos orígenes de datos, puede asociar los solucionadores a los campos de GraphQL en el esquema. La API ofrece las siguientes capacidades:

  • Crear una imagen a través del campo Mutation.createPicture

  • Crear una amistad a través del campo Mutation.createFriendship

  • Recuperar una imagen a través del campo Query.getPicture

Mutation.createPicture

En el editor de esquemas de la consola de AWS AppSync, elija a la derecha Asociar solucionador para createPicture(input: CreatePictureInput!): Picture!. Elija el origen de datos PicturesDynamoDBTableDynamoDB. En la sección Plantilla de mapeo de solicitudes, añada la siguiente plantilla:

#set($id = $util.autoId()) { "version" : "2018-05-29", "operation" : "PutItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($id), "owner": $util.dynamodb.toDynamoDBJson($ctx.args.input.owner) }, "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args.input) }

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

#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)

La funcionalidad de creación de imagen está lista. Va a guardar una imagen en la tabla Pictures (Imágenes) utilizando un UUID generado de forma aleatoria como id de la imagen y utilizando el nombre de usuario de Cognito como propietario de la imagen.

Mutation.createFriendship

En el editor de esquemas de la consola de AWS AppSync, elija a la derecha Asociar solucionador para createFriendship(id: ID!, target: ID!): Boolean. Elija el origen de datos DynamoDBFriendsDynamoDBTable. En la sección Plantilla de mapeo de solicitudes, añada la siguiente plantilla:

#set($userToFriendFriendship = { "userId" : "$ctx.args.id", "friendId": "$ctx.args.target" }) #set($friendToUserFriendship = { "userId" : "$ctx.args.target", "friendId": "$ctx.args.id" }) #set($friendsItems = [$util.dynamodb.toMapValues($userToFriendFriendship), $util.dynamodb.toMapValues($friendToUserFriendship)]) { "version" : "2018-05-29", "operation" : "BatchPutItem", "tables" : { ## Replace 'AppSyncTutorial-' default below with the ResourceNamePrefix you provided in the CloudFormation template "AppSyncTutorial-Friends": $util.toJson($friendsItems) } }

Importante: En la plantilla de solicitud BatchPutItem, el nombre exacto de la tabla de DynamoDB debería estar presente. El valor predeterminado de la tabla es AppSyncTutorial-Friends. Si utiliza el nombre de tabla erróneo, obtiene un error cuando AppSync intenta asumir el rol proporcionado.

En aras de simplificar este tutorial, continúe como si la solicitud de amistad se hubiera aprobado y guarde la entrada de relación directamente en la tabla AppSyncTutorialFriends.

Efectivamente, está almacenando dos elementos para cada amistad, ya que la relación es bidireccional. Para obtener información más detallada sobre las prácticas recomendadas de Amazon DynamoDB para representar las relaciones de varios a varios, consulte las prácticas recomendadas de DynamoDB.

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

#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end true

Nota: Asegúrese de que su plantilla de solicitud contiene el nombre de la tabla correcto. El nombre predeterminado es AppSyncTutorial-Friends, pero su nombre de tabla que puede ser diferentes si ha cambiado el parámetro ResourceNamePrefix de CloudFormation.

Query.getPicturesByOwner

Ahora que tiene amistades e imágenes, debe proporcionar la capacidad a los usuarios de ver las imágenes de sus amigos. Para cumplir este requisito, debe comprobar primero que el solicitante es amigo con el propietario y, por último, consultar las imágenes.

Dado que esta funcionalidad requiere dos operaciones de origen de datos, va a crear dos funciones. La primera función, isFriend, comprueba si el solicitante y el propietario son amigos. La segunda función, getPicturesByOwner, recupera las imágenes solicitadas dado un ID de propietario. Analicemos el flujo de ejecución por debajo del solucionador propuestos en el campo Query.getPicturesByOwner:

  1. Plantilla de mapeo Antes: Prepare los argumentos de entrada de contexto y campo.

  2. Función isFriend: Comprueba si el solicitante es el propietario de la imagen. En caso contrario, compruebe si los usuarios del solicitante y el propietario son amigos mediante una operación GetItem de DynamoDB en la tabla de amigos.

  3. Función getPicturesByOwner: recupera las imágenes de la tabla Imágenes mediante una operación de consulta de DynamoDB en el índice secundario global owner-index.

  4. Plantilla de mapeo Después: Mapea el resultado de la imagen para que los atributos de DynamoDB se mapeen correctamente en los campos de tipo GraphQL esperados.

Primero, vamos a crear las funciones.

Función isFriend
  1. Elija la pestaña Functions (Funciones).

  2. Elija Create Function (Crear función) para crear una función.

  3. Escriba FriendsDynamoDBTable como nombre del origen de datos.

  4. Para el nombre de la función, escriba isFriend.

  5. Dentro del área de texto de la plantilla de mapeo de solicitudes, pegue la siguiente plantilla:

    #set($ownerId = $ctx.prev.result.owner) #set($callerId = $ctx.prev.result.callerId) ## if the owner is the caller, no need to make the check #if($ownerId == $callerId) #return($ctx.prev.result) #end { "version" : "2018-05-29", "operation" : "GetItem", "key" : { "userId" : $util.dynamodb.toDynamoDBJson($callerId), "friendId" : $util.dynamodb.toDynamoDBJson($ownerId) } }
  6. Dentro del área de texto de la plantilla de mapeo de respuestas, pegue la siguiente plantilla:

    #if($ctx.error) $util.error("Unable to retrieve friend mapping message: ${ctx.error.message}", $ctx.error.type) #end ## if the users aren't friends #if(!$ctx.result) $util.unauthorized() #end $util.toJson($ctx.prev.result)
  7. Elija Create Function (Crear función).

Resultado: Ha creado la función isFriend.

Función getPicturesByOwner
  1. Elija la pestaña Functions (Funciones).

  2. Elija Create Function (Crear función) para crear una función.

  3. Escriba PicturesDynamoDBTable como nombre del origen de datos.

  4. Para el nombre de la función, escriba getPicturesByOwner.

  5. Dentro del área de texto de la plantilla de mapeo de solicitudes, pegue la siguiente plantilla:

    { "version" : "2018-05-29", "operation" : "Query", "query" : { "expression": "#owner = :owner", "expressionNames": { "#owner" : "owner" }, "expressionValues" : { ":owner" : $util.dynamodb.toDynamoDBJson($ctx.prev.result.owner) } }, "index": "owner-index" }
  6. Dentro del área de texto de la plantilla de mapeo de respuestas, pegue la siguiente plantilla:

    #if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)
  7. Elija Create Function (Crear función).

Resultado: Ha creado la función getPicturesByOwner. Ahora que las funciones se han creado, adjunte un solucionador de canalización al campo Query.getPicturesByOwner.

En el editor de esquemas de la consola de AWS AppSync, elija a la derecha Asociar solucionador para Query.getPicturesByOwner(id: ID!): [Picture]. En la página siguiente, elija el enlace Convert to pipeline resolver (Convertir a solucionador de canalización) que aparece debajo de la lista desplegable del origen de datos. Use lo siguiente para la plantilla de mapeo de antes:

#set($result = { "owner": $ctx.args.id, "callerId": $ctx.identity.username }) $util.toJson($result)

En la sección after mapping template (plantilla de mapeo de después), use lo siguiente:

#foreach($picture in $ctx.result.items) ## prepend "src://" to picture.src property #set($picture['src'] = "src://${picture['src']}") #end $util.toJson($ctx.result.items)

Elija Create Resolver (Crear solucionador). Acaba de asociar su primer solucionador de canalización. En la misma página, añada las dos funciones que ha creado anteriormente. En sección de funciones, seleccione Add A Function (Añadir una función) y, a continuación, elija o escriba el nombre de la primera función, isFriend. Añada la segunda función siguiendo el mismo proceso para la función getPicturesByOwner. Asegúrese de que la función isFriend aparece primero en la lista seguido de la función getPicturesByOwner. Puede utilizar las flechas hacia arriba y abajo para cambiar el orden de ejecución de las funciones de la canalización.

Ahora que el solucionador de canalización se ha creado y ha asociado las funciones, vamos a probar la nueva API de GraphQL.

Prueba de la API de GraphQL

En primer lugar, debe rellenar las imágenes y amistades ejecutando algunas mutaciones mediante el usuario administrador que ha creado. En el lateral izquierdo de la consola de AWS AppSync, elija la pestaña Consultas.

Mutación createPicture

  1. En la consola de AWS AppSync, elija la pestaña Consultas.

  2. Elija Login With User Pools (Inicio de sesión con grupos de usuarios).

  3. En el modal, introduzca el ID de cliente de Cognito de muestra que creó la pila de CloudFormation (por ejemplo, 37solo6mmhh7k4v63cqdfgdg5d).

  4. Escriba el nombre de usuario que ha pasado como parámetro a la pila de CloudFormation. El valor predeterminado es nadia.

  5. Utilice la contraseña temporal que se envió al correo electrónico que proporcionó como parámetro a la pila de CloudFormation (por ejemplo, UserPoolUserEmail).

  6. Seleccione Login (Iniciar sesión). Ahora debería poder ver el botón con el nuevo nombre Logout nadia (Cerrar sesión nadia) o cualquier nombre de usuario que haya elegido al crear la pila de CloudFormation (es decir, UserPoolUsername).

Vamos a enviar unas mutaciones de createPicture para rellenar la tabla de imágenes. Ejecute la siguiente consulta de GraphQL dentro de la consola:

mutation { createPicture(input:{ owner: "nadia" src: "nadia.jpg" }) { id owner src } }

La respuesta debe tener un aspecto similar al siguiente:

{ "data": { "createPicture": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "owner": "nadia", "src": "nadia.jpg" } } }

Agreguemos algunas imágenes más:

mutation { createPicture(input:{ owner: "shaggy" src: "shaggy.jpg" }) { id owner src } }
mutation { createPicture(input:{ owner: "rex" src: "rex.jpg" }) { id owner src } }

Ha agregado tres imágenes usando a nadia como usuario administrador.

Mutación createFriendship

Vamos a añadir una entrada de amistad. Ejecute las siguientes mutaciones en la consola.

Nota: Debe permanecer con la sesión iniciada como usuario administrador (el valor predeterminado es nadia).

mutation { createFriendship(id: "nadia", target: "shaggy") }

La respuesta debe tener un aspecto similar al siguiente:

{ "data": { "createFriendship": true } }

nadia y shaggy son amigos. rex no es amigo de nadie.

Consulta getPicturesByOwner

En este paso, inicie sesión como el usuario nadia con los grupos de usuarios de Cognito, con las credenciales configuradas al principio de este tutorial. Como nadia, recupere las imágenes propiedad de shaggy.

query { getPicturesByOwner(id: "shaggy") { id owner src } }

Dado que nadia y shaggy son amigos, la consulta debe devolver la imagen correspondiente.

{ "data": { "getPicturesByOwner": [ { "id": "05a16fba-cc29-41ee-a8d5-4e791f4f1079", "owner": "shaggy", "src": "src://shaggy.jpg" } ] } }

Del mismo modo, si nadia intenta recuperar sus propias imágenes, también se ejecuta satisfactoriamente. El solucionador de canalización se ha optimizado para evitar ejecutar la operación isFriend de GetItem en ese caso. Pruebe la siguiente consulta:

query { getPicturesByOwner(id: "nadia") { id owner src } }

Si habilita el registro en la API (en el panel Settings (Configuración)), configure el nivel de depuración a ALL (TODO) y ejecute la misma consulta de nuevo, devuelve los registros a la ejecución del campo. Observando los registros, puede determinar si la función isFriend se ha devuelto pronto en la etapa Request Mapping Template (Plantilla de mapeo de solicitud):

{ "errors": [], "mappingTemplateType": "Request Mapping", "path": "[getPicturesByOwner]", "resolverArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/types/Query/fields/getPicturesByOwner", "functionArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/functions/o2f42p2jrfdl3dw7s6xub2csdfs", "functionName": "isFriend", "earlyReturnedValue": { "owner": "nadia", "callerId": "nadia" }, "context": { "arguments": { "id": "nadia" }, "prev": { "result": { "owner": "nadia", "callerId": "nadia" } }, "stash": {}, "outErrors": [] }, "fieldInError": false }

La clave earlyReturnedValue representa los datos que devolvió la directiva #return.

Por último, aunque rex es miembro del grupo Viewers (Espectadores) de Cognito UserPool, dado que rex no es amigo de nadie, no podrá acceder a ninguna de las imágenes propiedad de shaggy o nadia. Si iniciar sesión como rex en la consola y ejecuta la siguiente consulta:

query { getPicturesByOwner(id: "nadia") { id owner src } }

Obtiene el siguiente error de no autorizado:

{ "data": { "getPicturesByOwner": null }, "errors": [ { "path": [ "getPicturesByOwner" ], "data": null, "errorType": "Unauthorized", "errorInfo": null, "locations": [ { "line": 2, "column": 9, "sourceName": null } ], "message": "Not Authorized to access getPicturesByOwner on type Query" } ] }

Ha implementado con éxito la autorización compleja con los solucionadores de canalización.