DEV Community

Eduardo Rabelo
Eduardo Rabelo

Posted on

Como Usar TypeScript com AWS AppSync Lambda Resolvers

Gerando tipos de TypeScript diretamente do seu esquema!

Um dos grandes benefícios do GraphQL é que ele é fortemente tipado! Defina seu esquema e GraphQL impõe a "forma" de entrada / saída de seus dados.

Se você estiver usando Lambda como resolvers do AWS AppSync com o tempo de execução Node.js, você também pode usar TypeScript. Se você fizer isso, você poderá definir os tipos de TypeScript que correspondem ao seu esquema automaticamente. Fazer isso manualmente pode ser entediante, e estaremos sujeito a erros e basicamente faremos o mesmo trabalho duas vezes! 🙁 Não seria ótimo se você pudesse importar seus tipos GraphQL para o seu código automaticamente?

Neste artigo, mostrarei como gerar tipos TypeScript diretamente do seu esquema GraphQL, apenas executando uma linha de comando! Em seguida, veremos como usar esses tipos em seus resolvers Lambda.

Vamos começar!

Pré-requisitos

Você já deve ter uma configuração de projeto do AWS AppSync com um esquema GraphQL definido (se ainda não tiver um, você pode usar o exemplo abaixo).

Para os fins deste tutorial, usaremos esse esquema como exemplo:

type Query {
  post(id: ID!): Post
}

type Mutation {
  createPost(post: PostInput!): Post!
}

type Post {
  id: ID!
  title: String!
  content: String!
  publishedAt: AWSDateTime
}

input PostInput {
  title: String!
  content: String!
}
Enter fullscreen mode Exit fullscreen mode

Configurando o projeto

Instale as dependências

Precisaremos instalar três pacotes:

npm i @graphql-codegen/cli @graphql-codegen/typescript @types/aws-lambda  -D
Enter fullscreen mode Exit fullscreen mode

Os primeiros dois pacotes pertencem a suite graphql-code-generator. O primeiro é a CLI base, enquanto o segundo é o plugin que gera o código TypeScript a partir de um esquema GraphQL.

@types/aws-lambda é uma coleção de tipos TypeScript para AWS Lambda. Inclui todos os tipos de definições de eventos Lambda (API Gateway, S3, SNS, etc.), incluindo uma para resolvers do AWS AppSync (AppSyncResolverHandler). Usaremos esse último mais tarde, quando construirmos nossos resolvers.

Crie o arquivo de configuração

É hora de configurar graphql-codegen e dizer como gerar nossos tipos TypeScript. Para isso, vamos criar um arquivo codegen.yml:

overwrite: true
schema:
  - schema.graphql # seu schema graphql

generates:
  appsync.d.ts:
    plugins:
      - typescript
Enter fullscreen mode Exit fullscreen mode

Isso diz ao codegen quais arquivos de esquema ele deve usar (no exemplo: schema.graphql), qual plugin (typescript) e onde a saída deve ser colocada (appsync.d.ts). Fique a vontade para alterar esses parâmetros para atender às suas necessidades.

Suporte para AWS Scalars

Se você estiver usando AWS AppSync Scalars, também precisará dizer ao graphql-codegen como lidar com eles.

💡 Você precisa declarar, no mínimo, os escalares que usa, mas pode ser uma boa ideia apenas declarar todos eles.

Vamos criar um novo arquivo appsync.graphql com o seguinte conteúdo:

scalar AWSDate
scalar AWSTime
scalar AWSDateTime
scalar AWSTimestamp
scalar AWSEmail
scalar AWSJSON
scalar AWSURL
scalar AWSPhone
scalar AWSIPAddress
Enter fullscreen mode Exit fullscreen mode

⚠️ Não coloque esses tipos no mesmo arquivo de seu esquema principal. Você só precisa deles para geração de código e eles não devem entrar em seu deploy para o AWS AppSync.

Também precisamos dizer ao codegen como mapear esses escalares para o TypeScript. Para isso, iremos modificar o arquivo codegen.yml. Adicione / edite as seguintes seções:

schema:
  - schema.graphql
  - appsync.graphql # 👈 coloco isso

# e isso 👇
config:
  scalars:
    AWSJSON: string
    AWSDate: string
    AWSTime: string
    AWSDateTime: string
    AWSTimestamp: number
    AWSEmail: string
    AWSURL: string
    AWSPhone: string
    AWSIPAddress: string
Enter fullscreen mode Exit fullscreen mode

Gerando o código

Estamos prontos com a configuração. É hora de gerar algum código! Execute o seguinte comando:

graphql-codegen
Enter fullscreen mode Exit fullscreen mode

💡 Você também pode adicionar "codegen": "graphql-codegen" ao seu package.json na seção "scripts" e usar npm run codegen.

Se você olhar em seu diretório de trabalho, verá um arquivo appsync.d.ts que contém os tipos gerados.

export type Maybe<T> = T | null;
export type Exact<T extends { [key: string]: unknown }> = {
  [K in keyof T]: T[K];
};
export type MakeOptional<T, K extends keyof T> = Omit<T, K> &
  { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> &
  { [SubKey in K]: Maybe<T[SubKey]> };

/** Todos os AWS AppSync Scalars, mapeados para seus atuais valores */
export type Scalars = {
  ID: string;
  String: string;
  Boolean: boolean;
  Int: number;
  Float: number;
  AWSDate: string;
  AWSTime: string;
  AWSDateTime: string;
  AWSTimestamp: number;
  AWSEmail: string;
  AWSJSON: string;
  AWSURL: string;
  AWSPhone: string;
  AWSIPAddress: string;
};

export type Query = {
  __typename?: "Query";
  post?: Maybe<Post>;
};

export type QueryPostArgs = {
  id: Scalars["ID"];
};

export type Mutation = {
  __typename?: "Mutation";
  createPost: Post;
};

export type MutationCreatePostArgs = {
  post: PostInput;
};

export type Post = {
  __typename?: "Post";
  id: Scalars["ID"];
  title: Scalars["String"];
  content: Scalars["String"];
  publishedAt?: Maybe<Scalars["AWSDateTime"]>;
};

export type PostInput = {
  title: Scalars["String"];
  content: Scalars["String"];
};
Enter fullscreen mode Exit fullscreen mode

Observe que, além de alguns tipos auxiliares na parte superior, diferentes tipos estão sendo gerados:

  • Scalars

Contém todos os escalares básicos (ID, String, etc.) e os escalares personalizados da AWS.

  • Query e Mutation

Esses dois tipos descrevem os tipos completos de consulta e mutação.

  • Post

Este é o nosso tipo Post de nosso esquema traduzido para TypeScript. É também o valor de retorno da query post e da mutação createPost.

  • QueryPostArgs e MutationCreatePostArgs

Esses tipos descrevem os argumentos de entrada da query post e da mutação createPost, respectivamente.

💡 Você notou o padrão de nome aqui? Os tipos de argumento são sempre nomeados Query[NomeDoEndpoint]Args e Mutation[NomeDoEndpoint]Args em PascalCase. Isso é útil para saber quando você deseja preencher automaticamente os tipos em seu IDE.

Usando os tipos gerados

Agora que geramos nossos tipos, é hora de usá-los!

Vamos implementar o resolver Query.post como exemplo.

Os manipuladores de lambda sempre recebem 3 argumentos:

  • event: contém informações sobre a consulta de entrada (argumentos, identidade, etc)
  • context: contém informações sobre a função Lambda executada
  • callback: uma função que você pode chamar quando seu manipulador for finalizado (se você não estiver usando async/Promise)

A forma de um manipulador do AWS AppSync é quase sempre a mesma. Acontece que existe um pacote DefinitelyTyped que já o define. Nós o instalamos no início deste tutorial. Vamos usar!

O tipo AppSyncResolverHandler leva dois argumentos. O primeiro é o tipo do objeto event.arguments e o segundo é o valor de retorno do resolver.

No nosso caso, será: QueryPostArgs e Post, respectivamente.

Aqui está como usá-lo:

import db from "./db";
import { AppSyncResolverHandler } from "aws-lambda";
import { Post, QueryPostArgs } from "./appsync";

export const handler: AppSyncResolverHandler<QueryPostArgs, Post> = async (
  event
) => {
  const post = await db.getPost(event.arguments.id);

  if (post) {
    return post;
  }

  throw new Error("Not Found");
};
Enter fullscreen mode Exit fullscreen mode

Agora, nosso manipulador Lambda se beneficia da verificação de tipo de 2 maneiras:

  • event.arguments: Será do tipo QueryPostArgs (com os benefícios do preenchimento automático!)
  • verificação do valor de retorno, ou o segundo argumento de callback, tenha a mesma forma que Post (com um id, título, etc); ou o TypeScript mostrará um erro.

Uso avançado

Existem muitas opções que permitem personalizar os tipos gerados. Confira a documentação para mais detalhes!

Conclusão

Com a geração automática de tipos, você não apenas melhorará sua velocidade de desenvolvimento e experiência, mas também garantirá que seus resolvers façam o que sua API espera. Você também garante que seus tipos de código e seus tipos de esquema estejam sempre em perfeita sincronia, evitando incompatibilidades que podem levar a bugs.

Não se esqueça de executar novamente o comando graphql-codegen cada vez que editar seu esquema! Pode ser uma boa ideia automatizar o processo ou validar seus tipos no pipeline de CI / CD.


Créditos

Top comments (0)