Uso de un AWS AppSync API con AWS CDK - 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.

Uso de un AWS AppSync API con AWS CDK

sugerencia

Antes de usar elCDK, te recomendamos revisar CDK la documentación oficial junto con AWS AppSync su CDKreferencia.

También le recomendamos que se asegure de que su sistema AWS CLIy sus NPMinstalaciones funcionan correctamente.

En esta sección, vamos a crear una CDK aplicación sencilla que pueda añadir y recuperar elementos de una tabla de DynamoDB. Se trata de un ejemplo de inicio rápido en el que se utiliza parte del código de las secciones Diseñar un esquema, Adjuntar una fuente de datos y Configurar resolutores (). JavaScript

Configuración de un proyecto CDK

aviso

Es posible que estos pasos no sean completamente precisos en función del entorno. Suponemos que su sistema tiene instaladas las utilidades necesarias, una forma de interactuar con AWS los servicios y las configuraciones adecuadas.

El primer paso es instalar el AWS CDK. En suCLI, puede introducir el siguiente comando:

npm install -g aws-cdk

A continuación, debe crear un directorio del proyecto y, luego, navegar hasta él. Un ejemplo de un conjunto de comandos para crear un directorio y navegar a él es:

mkdir example-cdk-app cd example-cdk-app

A continuación, debe crear una aplicación. Nuestro servicio utiliza principalmente TypeScript. Ejecute el siguiente comando en el directorio de su proyecto:

cdk init app --language typescript

Al hacerlo, se instalará una CDK aplicación junto con sus archivos de inicialización:

Terminal output showing Git repository initialization and npm install completion.

La estructura de proyecto puede tener un aspecto similar al siguiente:

Project directory structure showing folders and files for an example CDK app.

Se dará cuenta de que tenemos varios directorios importantes:

  • bin: el archivo bin inicial creará la aplicación. No trataremos este tema en esta guía.

  • lib: el directorio lib contiene los archivos de pila. Los archivos de pila se podrían comparar a unidades de ejecución individuales. Las construcciones estarán dentro de nuestros archivos de pila. Básicamente, se trata de recursos para un servicio que se activará AWS CloudFormation cuando se despliegue la aplicación. Aquí es donde se realizará la mayor parte de nuestra codificación.

  • node_modules: Este directorio lo crea NPM y contiene todas las dependencias de paquetes que instaló mediante el npm comando.

Nuestro archivo de pila inicial puede contener algo como esto:

import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; // import * as sqs from 'aws-cdk-lib/aws-sqs'; export class ExampleCdkAppStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // The code that defines your stack goes here // example resource // const queue = new sqs.Queue(this, 'ExampleCdkAppQueue', { // visibilityTimeout: cdk.Duration.seconds(300) // }); } }

Este es el código reutilizable para crear una pila en nuestra aplicación. La mayor parte del código de este ejemplo se incluirá en el ámbito de esta clase.

Para comprobar que el archivo de pila está en la aplicación, en el directorio de la aplicación, ejecute el siguiente comando en el terminal:

cdk ls

Debería aparecer una lista de sus pilas. Si no es así, es posible que tenga que volver a realizar los pasos o consultar la documentación oficial para obtener ayuda.

Si quiere compilar los cambios de código antes de implementarlos, siempre puede ejecutar el siguiente comando en el terminal:

npm run build

Y, para ver los cambios antes de la implementación:

cdk diff

Antes de añadir nuestro código al archivo de pila, vamos a realizar un arranque. El arranque nos permite aprovisionar recursos CDK antes de que se despliegue la aplicación. Puede encontrar más información sobre este proceso aquí. El comando para crear un arranque es:

cdk bootstrap aws://ACCOUNT-NUMBER/REGION
sugerencia

Este paso requiere varios IAM permisos en tu cuenta. Se denegará el arranque si no los tiene. Si esto ocurre, es posible que tenga que eliminar los recursos incompletos que ha causado el arranque, como el bucket de S3 que genera.

El arranque generará varios recursos. El mensaje final tendrá el siguiente aspecto:

Terminal output showing successful bootstrapping of an AWS environment.

Esto se hace una vez por cuenta y región, por lo que no tendrá que hacerlo con frecuencia. Los principales recursos del bootstrap son la AWS CloudFormation pila y el bucket de Amazon S3.

El bucket de Amazon S3 se utiliza para almacenar archivos y IAM funciones que conceden los permisos necesarios para realizar las implementaciones. Los recursos necesarios se definen en una AWS CloudFormation pila, denominada pila bootstrap, que suele tener ese nombre. CDKToolkit Como cualquier AWS CloudFormation pila, aparece en la AWS CloudFormation consola una vez desplegada:

CDKToolkit stack with CREATE_COMPLETE status in AWS CloudFormation console.

Lo mismo puede decirse del bucket:

S3 bucket details showing name, region, access settings, and creation date.

Para importar los servicios que necesitamos en nuestro archivo de pila, podemos usar el siguiente comando:

npm install aws-cdk-lib # V2 command
sugerencia

Si tiene problemas con la V2, puede instalar las bibliotecas individuales mediante los comandos de la V1:

npm install @aws-cdk/aws-appsync @aws-cdk/aws-dynamodb

No recomendamos esta opción porque la V1 está en desuso.

Implementación de un CDK proyecto: esquema

Ahora podemos empezar a implementar nuestro código. En primer lugar, debemos crear nuestro esquema. Simplemente puede crear un archivo .graphql en su aplicación:

mkdir schema touch schema.graphql

En nuestro ejemplo, incluimos un directorio de nivel superior llamado schema que contiene nuestro schema.graphql:

File structure showing a schema folder containing schema.graphql file.

Dentro de nuestro esquema, vamos a incluir un ejemplo sencillo:

input CreatePostInput { title: String content: String } type Post { id: ID! title: String content: String } type Mutation { createPost(input: CreatePostInput!): Post } type Query { getPost: [Post] }

De vuelta a nuestro archivo de pila, debemos asegurarnos de que estén definidas las siguientes directivas de importación:

import * as cdk from 'aws-cdk-lib'; import * as appsync from 'aws-cdk-lib/aws-appsync'; import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; import { Construct } from 'constructs';

Dentro de la clase, añadiremos código para crear nuestro GraphQL API y conectarlo a nuestro schema.graphql archivo:

export class ExampleCdkAppStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // makes a GraphQL API const api = new appsync.GraphqlApi(this, 'post-apis', { name: 'api-to-process-posts', schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'), }); } }

También añadiremos código para imprimir el GraphQLURL, la API clave y la región:

export class ExampleCdkAppStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Makes a GraphQL API construct const api = new appsync.GraphqlApi(this, 'post-apis', { name: 'api-to-process-posts', schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'), }); // Prints out URL new cdk.CfnOutput(this, "GraphQLAPIURL", { value: api.graphqlUrl }); // Prints out the AppSync GraphQL API key to the terminal new cdk.CfnOutput(this, "GraphQLAPIKey", { value: api.apiKey || '' }); // Prints out the stack region to the terminal new cdk.CfnOutput(this, "Stack Region", { value: this.region }); } }

En este punto, volveremos a implementar nuestra aplicación:

cdk deploy

El resultado es el siguiente:

Deployment output showing ExampleCdkAppStack details, including GraphQL API URL and stack region.

Parece que nuestro ejemplo fue exitoso, pero revisemos la AWS AppSync consola para confirmarlo:

GraphQL interface showing successful API request with response data displayed.

Parece que el nuestro API fue creado. Ahora, comprobaremos el esquema adjunto aAPI:

GraphQL schema defining CreatePostInput, Post type, Mutation, and Query operations.

Esto parece coincidir con nuestro código de esquema, por lo que se ha realizado correctamente. Otra forma de confirmarlo desde el punto de vista de los metadatos es observar la AWS CloudFormation pila:

AWS CloudFormation stack showing ExampleCdkAppStack update complete and CDKToolkit creation complete.

Cuando implementamos nuestra CDK aplicación, esta activa AWS CloudFormation recursos, como el bootstrap. Cada pila de nuestra aplicación se mapea 1:1 con una AWS CloudFormation pila. Si vuelve al código de la pila, verá que el nombre de la pila se ha tomado del nombre de la claseExampleCdkAppStack. Puedes ver los recursos que creó, que también coinciden con nuestras convenciones de nomenclatura en nuestra construcción GraphQLAPI:

Expanded view of post-apis resource showing Schema, DefaultApiKey, and CDKMetadata.

Implementación de un CDK proyecto: fuente de datos

A continuación, debemos añadir nuestro origen de datos. En nuestro ejemplo, se utilizará una tabla de DynamoDB. Dentro de la clase de pila, añadiremos código para crear una tabla nueva:

export class ExampleCdkAppStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Makes a GraphQL API construct const api = new appsync.GraphqlApi(this, 'post-apis', { name: 'api-to-process-posts', schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'), }); //creates a DDB table const add_ddb_table = new dynamodb.Table(this, 'posts-table', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING, }, }); // Prints out URL new cdk.CfnOutput(this, "GraphQLAPIURL", { value: api.graphqlUrl }); // Prints out the AppSync GraphQL API key to the terminal new cdk.CfnOutput(this, "GraphQLAPIKey", { value: api.apiKey || '' }); // Prints out the stack region to the terminal new cdk.CfnOutput(this, "Stack Region", { value: this.region }); } }

Llegados a este punto, volvamos a implementarla:

cdk deploy

Deberíamos comprobar la consola de DynamoDB para ver nuestra nueva tabla:

DynamoDB console showing ExampleCdkAppStack-poststable as Active with Provisioned capacity.

El nombre de nuestra pila es correcto y el nombre de la tabla coincide con nuestro código. Si volvemos a comprobar nuestra AWS CloudFormation pila, ahora veremos la nueva tabla:

Expanded view of a logical ID in AWS CloudFormation showing post-apis, posts-table, and CDKMetadata.

Implementación de un CDK proyecto: Resolver

En este ejemplo, se utilizarán dos solucionadores: uno para consultar la tabla y otro para añadirle elementos. Como utilizamos solucionadores de canalizaciones, tendremos que declarar dos solucionadores de canalizaciones con una función en cada uno. En la consulta, añadiremos el siguiente código:

export class ExampleCdkAppStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Makes a GraphQL API construct const api = new appsync.GraphqlApi(this, 'post-apis', { name: 'api-to-process-posts', schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'), }); //creates a DDB table const add_ddb_table = new dynamodb.Table(this, 'posts-table', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING, }, }); // Creates a function for query const add_func = new appsync.AppsyncFunction(this, 'func-get-post', { name: 'get_posts_func_1', api, dataSource: api.addDynamoDbDataSource('table-for-posts', add_ddb_table), code: appsync.Code.fromInline(` export function request(ctx) { return { operation: 'Scan' }; } export function response(ctx) { return ctx.result.items; } `), runtime: appsync.FunctionRuntime.JS_1_0_0, }); // Creates a function for mutation const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', { name: 'add_posts_func_1', api, dataSource: api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table), code: appsync.Code.fromInline(` export function request(ctx) { return { operation: 'PutItem', key: util.dynamodb.toMapValues({id: util.autoId()}), attributeValues: util.dynamodb.toMapValues(ctx.args.input), }; } export function response(ctx) { return ctx.result; } `), runtime: appsync.FunctionRuntime.JS_1_0_0, }); // Adds a pipeline resolver with the get function new appsync.Resolver(this, 'pipeline-resolver-get-posts', { api, typeName: 'Query', fieldName: 'getPost', code: appsync.Code.fromInline(` export function request(ctx) { return {}; } export function response(ctx) { return ctx.prev.result; } `), runtime: appsync.FunctionRuntime.JS_1_0_0, pipelineConfig: [add_func], }); // Adds a pipeline resolver with the create function new appsync.Resolver(this, 'pipeline-resolver-create-posts', { api, typeName: 'Mutation', fieldName: 'createPost', code: appsync.Code.fromInline(` export function request(ctx) { return {}; } export function response(ctx) { return ctx.prev.result; } `), runtime: appsync.FunctionRuntime.JS_1_0_0, pipelineConfig: [add_func_2], }); // Prints out URL new cdk.CfnOutput(this, "GraphQLAPIURL", { value: api.graphqlUrl }); // Prints out the AppSync GraphQL API key to the terminal new cdk.CfnOutput(this, "GraphQLAPIKey", { value: api.apiKey || '' }); // Prints out the stack region to the terminal new cdk.CfnOutput(this, "Stack Region", { value: this.region }); } }

En este fragmento, añadimos un solucionador de canalizaciones llamado pipeline-resolver-create-posts con una función llamada func-add-post asociada. Este es el código que añadirá Posts a la tabla. El otro solucionador de canalizaciones se ha denominado pipeline-resolver-get-posts, con una función llamada func-get-post que recupera Posts añadidos a la tabla.

Implementaremos esto para añadirlo al AWS AppSync servicio:

cdk deploy

Comprobemos la AWS AppSync consola para ver si estaban conectados a nuestro GraphQLAPI:

GraphQL API schema showing mutation and query fields with Pipeline resolvers.

Parece correcto. En el código, estos dos resolutores estaban adjuntos al API GraphQL que creamos (indicado por el valor props presente tanto en api los resolutores como en las funciones). En GraphQLAPI, los campos a los que adjuntábamos nuestros resolutores también se especificaban en los accesorios (definidos por los typename y los fieldname accesorios de cada resolutor).

Veamos si el contenido de los solucionadores es correcto empezando por pipeline-resolver-get-posts:

Code snippet showing request and response functions in a resolver, with an arrow pointing to them.

Los controladores de antes y después coinciden con nuestro valor de accesorios code. También podemos ver una función llamada add_posts_func_1, que coincide con el nombre de la función que asociamos en el solucionador.

Veamos el contenido del código de esa función:

Function code showing request and response methods for a PutItem operation.

Esto coincide con los accesorios code de la función add_posts_func_1. Nuestra consulta se ha cargado correctamente, así que revisemos la consulta:

Resolver code with request and response functions, and a get_posts_func_1 function listed below.

También coinciden con el código. Si nos fijamos en get_posts_func_1:

Code snippet showing two exported functions: request returning 'Scan' operation and response returning items.

Todo parece estar en su sitio. Para confirmarlo desde el punto de vista de los metadatos, podemos volver a revisar nuestra pila en AWS CloudFormation :

List of logical IDs for AWS resources including API, table, functions, and pipelines.

Ahora, necesitamos probar este código realizando algunas solicitudes.

Implementación de un proyecto: solicitudes CDK

Para probar nuestra aplicación en la AWS AppSync consola, hicimos una consulta y una mutación:

GraphQL code snippet showing a query to get post details and a mutation to create a post.

MyMutation contiene una operación createPost con los argumentos 1970-01-01T12:30:00.000Z y first post. Devuelve los date y title que hemos introducido, así como el valor id generado automáticamente. Al ejecutar la mutación, se obtiene el resultado:

{ "data": { "createPost": { "date": "1970-01-01T12:30:00.000Z", "id": "4dc1c2dd-0aa3-4055-9eca-7c140062ada2", "title": "first post" } } }

Si comprobamos rápidamente la tabla de DynamoDB, podemos ver nuestra entrada en la tabla cuando la escaneamos:

DynamoDB table entry showing id, date, and title fields for a single item.

Al volver a la AWS AppSync consola, si ejecutamos la consulta para recuperarloPost, obtenemos el siguiente resultado:

{ "data": { "getPost": [ { "id": "9f62c4dd-49d5-48d5-b835-143284c72fe0", "date": "1970-01-01T12:30:00.000Z", "title": "first post" } ] } }