|
| 1 | +--- |
| 2 | +title: AppSync GraphQL |
| 3 | +description: Event Handler for AppSync GraphQL APIs |
| 4 | +status: new |
| 5 | +--- |
| 6 | + |
| 7 | +Event Handler for AWS AppSync GraphQL APIs simplifies routing and processing of events in AWS Lambda functions. It allows you to define resolvers for GraphQL types and fields, making it easier to handle GraphQL requests without the need for complex VTL or JavaScript templates. |
| 8 | + |
| 9 | +```mermaid |
| 10 | +--8<-- "examples/snippets/event-handler/appsync-graphql/diagrams/intro.mermaid" |
| 11 | +``` |
| 12 | + |
| 13 | +## Key Features |
| 14 | + |
| 15 | +- Route events based on GraphQL type and field keys |
| 16 | +- Automatically parse API arguments to function parameters |
| 17 | +- Handle GraphQL responses and errors in the expected format |
| 18 | + |
| 19 | +## Terminology |
| 20 | + |
| 21 | +**[Direct Lambda Resolver](https://docs.aws.amazon.com/appsync/latest/devguide/direct-lambda-reference.html){target="_blank"}**. A custom AppSync Resolver that bypasses Apache Velocity Template (VTL) and JavaScript templates, and automatically maps your function's response to a GraphQL field. |
| 22 | + |
| 23 | +**[Batching resolvers](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html#advanced-use-case-batching){target="_blank"}**. A technique that allows you to batch multiple GraphQL requests into a single Lambda function invocation, reducing the number of calls and improving performance. |
| 24 | + |
| 25 | +## Getting started |
| 26 | + |
| 27 | +???+ tip "Tip: Designing GraphQL Schemas for the first time?" |
| 28 | + Visit [AWS AppSync schema documentation](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html){target="_blank"} to understand how to define types, nesting, and pagination. |
| 29 | + |
| 30 | +### Required resources |
| 31 | + |
| 32 | +You must have an existing AppSync GraphQL API and IAM permissions to invoke your Lambda function. That said, there is no additional permissions to use Event Handler as routing requires no dependency (_standard library_). |
| 33 | + |
| 34 | +This is the sample infrastructure we will be using for the initial examples with an AppSync Direct Lambda Resolver. |
| 35 | + |
| 36 | +=== "gettingStartedSchema.graphql" |
| 37 | + |
| 38 | + ```typescript |
| 39 | + --8<-- "examples/snippets/event-handler/appsync-graphql/templates/gettingStartedSchema.graphql" |
| 40 | + ``` |
| 41 | + |
| 42 | +=== "template.yaml" |
| 43 | + |
| 44 | + ```yaml hl_lines="59-60 71-72 94-95 104-105 112-113" |
| 45 | + --8<-- "examples/snippets/event-handler/appsync-graphql/templates/gettingStartedSam.yaml" |
| 46 | + ``` |
| 47 | + |
| 48 | +### Registering a resolver |
| 49 | + |
| 50 | +You can register functions to match GraphQL types and fields with one of three methods: |
| 51 | + |
| 52 | +- `onQuery()` - Register a function to handle a GraphQL Query type. |
| 53 | +- `onMutation()` - Register a function to handle a GraphQL Mutation type. |
| 54 | +- `resolver()` - Register a function to handle a GraphQL type and field. |
| 55 | + |
| 56 | +!!! question "What is a type and field?" |
| 57 | + A type would be a top-level **GraphQL Type** like `Query`, `Mutation`, `Todo`. A **GraphQL Field** would be `listTodos` under `Query`, `createTodo` under `Mutation`, etc. |
| 58 | + |
| 59 | +The function receives the parsed arguments from the GraphQL request as its first parameter. We also take care of parsing the response or catching errors and returning them in the expected format. |
| 60 | + |
| 61 | +#### Query resolver |
| 62 | + |
| 63 | +When registering a resolver for a `Query` type, you can use the `onQuery()` method. This method allows you to define a function that will be invoked when a GraphQL Query is made. |
| 64 | + |
| 65 | +```typescript hl_lines="2 8 10 21" title="Registering a resolver for a Query type" |
| 66 | +--8<-- "examples/snippets/event-handler/appsync-graphql/gettingStartedOnQuery.ts" |
| 67 | +``` |
| 68 | + |
| 69 | +#### Mutation resolver |
| 70 | + |
| 71 | +Similarly, you can register a resolver for a `Mutation` type using the `onMutation()` method. This method allows you to define a function that will be invoked when a GraphQL Mutation is made. |
| 72 | + |
| 73 | +```typescript hl_lines="2-5 11 13 25" title="Registering a resolver for a Mutation type" |
| 74 | +--8<-- "examples/snippets/event-handler/appsync-graphql/gettingStartedOnMutation.ts" |
| 75 | +``` |
| 76 | + |
| 77 | +#### Generic resolver |
| 78 | + |
| 79 | +When you want to have more control over the type and field, you can use the `resolver()` method. This method allows you to register a function for a specific GraphQL type and field including custom types. |
| 80 | + |
| 81 | +```typescript hl_lines="2 8 10 27-30" title="Registering a resolver for a type and field" |
| 82 | +--8<-- "examples/snippets/event-handler/appsync-graphql/gettingStartedResolver.ts" |
| 83 | +``` |
| 84 | + |
| 85 | +#### Using decorators |
| 86 | + |
| 87 | +If you prefer to use the decorator syntax, you can instead use the same methods on a class method to register your handlers. Learn more about how Powertools for TypeScript supports [decorators](../../getting-started/usage-patterns.md). |
| 88 | + |
| 89 | +```typescript hl_lines="3-6 12 15 27 38 60" title="Using decorators to register a resolver" |
| 90 | +--8<-- "examples/snippets/event-handler/appsync-graphql/gettingStartedDecorators.ts" |
| 91 | +``` |
| 92 | + |
| 93 | +1. It's recommended to pass a refernce of `this` to ensure the correct class scope is propageted to the route handler functions. |
| 94 | + |
| 95 | +### Scalar functions |
| 96 | + |
| 97 | +When working with [AWS AppSync Scalar types](https://docs.aws.amazon.com/appsync/latest/devguide/scalars.html){target="_blank"}, you might want to generate the same values for data validation purposes. |
| 98 | + |
| 99 | +For convenience, the most commonly used values are available as helper functions within the module. |
| 100 | + |
| 101 | +```typescript hl_lines="2-6" title="Creating key scalar values" |
| 102 | +--8<-- "examples/snippets/event-handler/appsync-graphql/gettingStartedScalarFunctions.ts" |
| 103 | +``` |
| 104 | + |
| 105 | +Here's a table with their related scalar as a quick reference: |
| 106 | + |
| 107 | +| Scalar type | Scalar function | Sample value | |
| 108 | +| ---------------- | --------------- | -------------------------------------- | |
| 109 | +| **ID** | `makeId` | `e916c84d-48b6-484c-bef3-cee3e4d86ebf` | |
| 110 | +| **AWSDate** | `awsDate` | `2022-07-08Z` | |
| 111 | +| **AWSTime** | `awsTime` | `15:11:00.189Z` | |
| 112 | +| **AWSDateTime** | `awsDateTime` | `2022-07-08T15:11:00.189Z` | |
| 113 | +| **AWSTimestamp** | `awsTimestamp` | `1657293060` | |
| 114 | + |
| 115 | +## Advanced |
| 116 | + |
| 117 | +### Nested mappings |
| 118 | + |
| 119 | +!!! note |
| 120 | + |
| 121 | + The following examples use a more advanced schema. These schemas differ from the [initial sample infrastructure we used earlier](#required-resources). |
| 122 | + |
| 123 | +You can register the same route handler multiple times to resolve fields with the same return value. |
| 124 | + |
| 125 | +=== "Nested Mappings Example" |
| 126 | + |
| 127 | + ```typescript hl_lines="8 33-39" |
| 128 | + --8<-- "examples/snippets/event-handler/appsync-graphql/advancedNestedMappings.ts" |
| 129 | + ``` |
| 130 | + |
| 131 | + 1. If omitted, the `typeName` defaults to `Query`. |
| 132 | + |
| 133 | +=== "Nested Mappings Schema" |
| 134 | + |
| 135 | + ```graphql hl_lines="6 20" |
| 136 | + --8<-- "examples/snippets/event-handler/appsync-graphql/templates/advancedNestedMappingsSchema.graphql" |
| 137 | + ``` |
| 138 | + |
| 139 | +### Accessing Lambda context and event |
| 140 | + |
| 141 | +You can access the original Lambda event or context for additional information. These are passed to the handler function as optional arguments. |
| 142 | + |
| 143 | +=== "Access event and context" |
| 144 | + |
| 145 | + ```typescript hl_lines="10" |
| 146 | + --8<-- "examples/snippets/event-handler/appsync-graphql/advancedAccessEventAndContext.ts" |
| 147 | + ``` |
| 148 | + |
| 149 | + 1. The `event` parameter contains the original AppSync event and has type `AppSyncResolverEvent` from the `@types/aws-lambda`. |
| 150 | + |
| 151 | +### Logging |
| 152 | + |
| 153 | +By default, the utility uses the global `console` logger and emits only warnings and errors. |
| 154 | + |
| 155 | +You can change this behavior by passing a custom logger instance to the `AppSyncGraphQLResolver` or `Router` and setting the log level for it, or by enabling [Lambda Advanced Logging Controls](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs-advanced.html) and setting the log level to `DEBUG`. |
| 156 | + |
| 157 | +When debug logging is enabled, the resolver will emit logs that show the underlying handler resolution process. This is useful for understanding how your handlers are being resolved and invoked and can help you troubleshoot issues with your event processing. |
| 158 | + |
| 159 | +For example, when using the [Powertools for AWS Lambda logger](../logger.md), you can set the `LOG_LEVEL` to `DEBUG` in your environment variables or at the logger level and pass the logger instance to the constructor to enable debug logging. |
| 160 | + |
| 161 | +=== "Debug logging" |
| 162 | + |
| 163 | + ```typescript hl_lines="11" |
| 164 | + --8<-- "examples/snippets/event-handler/appsync-graphql/advancedDebugLogging.ts" |
| 165 | + ``` |
| 166 | + |
| 167 | +=== "Logs output" |
| 168 | + |
| 169 | + ```json |
| 170 | + --8<-- "examples/snippets/event-handler/appsync-graphql/samples/debugLogExcerpt.json" |
| 171 | + ``` |
| 172 | + |
| 173 | +## Testing your code |
| 174 | + |
| 175 | +You can test your resolvers by passing an event with the shape expected by the AppSync GraphQL API resolver. |
| 176 | + |
| 177 | +Here's an example of how you can test your resolvers that uses a factory function to create the event shape: |
| 178 | + |
| 179 | +```typescript |
| 180 | +--8<-- "examples/snippets/event-handler/appsync-graphql/advancedTestYourCode.ts" |
| 181 | +``` |
0 commit comments