GraphQL _ How To Build GraphQL Resolvers for AWS Data Sources _ Amazon Web Services (AWS)
GraphQL _ How To Build GraphQL Resolvers for AWS Data Sources _ Amazon Web Services (AWS)
JavaScript
1 const resolvers = {
2 Query: {
3 hello: () => { return 'Hello world!'},
4 },};
JavaScript
1 Mutation: {
2 login: async (_, { email }, { dataSources }) => {
3 const user = await dataSources.userAPI.findOrCreateUser({ em
4
5 if (user) {
6 user.token = Buffer.from(email).toString('base64');
7 return user;
8 }
9 },},
Copy
The login scenario above shows how GraphQL resolvers can become more complex. Moreover, it
highlights how it might be necessary to reach out to other systems, call other functions, and perform other
calls to build the return object for the query or mutation.
In the following snippet, Apollo Library and SDK are used to perform several key steps: configuration for
the connection, instantiation of the DocumentClient, and then executing these for a put against the
database.
JavaScript
Copy
For additional information on building out access and usage plans, see the DynamoDB Documentation
Developer Guide and the Apollo Documentation.
This is an example of an Apollo GraphQL resolver with a PostgreSQL database using the pg client for
Node.js and the SDK.
JavaScript
Copy
This example demonstrates Amazon RDS and PostgreSQL specificities. The connection pooling that a
relational database does – whether PostgreSQL, MySQL, SQL Server, or another – is an important part of
the connection that must be managed.
Get Started for Free Contact Us
For more information on writing queries against Amazon RDS and Aurora, see documentation on
Amazon RDS Proxy; for more on PostgreSQL pooling for pg, see Pooling Documentation.
Parameters are built up and passed to the Lambda function and the call within the GraphQL resolver.
JavaScript
Use AWS SDKs for all calls to AWS resources. This will ensure a consistent, reliable, and maintained
access method for GraphQL APIs and their respective data sources.
The SDK provides a more consistent way to setup configuration; pass secrets for connections; handle
errors, retries, and exponential back off; and other important aspects across the code base. Using the SDK
also makes it easier to set up a particular access style, such as async await, promises, or callbacks. There
are many additional reasons to use the SDK beyond these immediate advantages.
JavaScript
Copy
Name all the operations, parameters, and other passed code mapped with their respective database
queries across their layers of concern.
For example, if the GraphQL query is to get movies, and it looks like this example, ensure that the
respective query on the database side matches the names or naming. The table in the database should be
named movie or movies, depending on the convention. Moreover, this all leads to a better understanding
and readability when determining which GraphQL query belongs to which database query, database table,
and so on. This prevents the multiple layers of GraphQL query or mutation and entity with fields from
getting confused or out of synchronization with the database. Furthermore, when options present
themselves, this provides an easier path to automation if code generation or other technologies are used
to create resolvers.
JavaScript
1 query GetMovies{
2 movies {
3 title
4 Get Started
year for Free Contact Us
5 }
6 }
Copy
Determine a strategy to maintain a clear tactical understanding of what behavior to expect from the API.
For example, a good practice to follow is writing code against a determined (based on desired outcomes)
connection method. If a database is setup and the intent is to use a service such as Amazon RDS Proxy to
implement connection pooling, ensure that driver code is written for the GraphQL resolvers to match that
architectural decision. If a client connection must fire and forget, this needs to be taken into account.
Otherwise, if a client must set up a connection and interact with multiple queries per resolver, that must
be part of the design patterns used. This prevents resolvers from being written that deviate from expected
usage, which would result in few to no errors or warnings and an almost impossible situation to debug.
4. Authorization
Determine what authorization strategy will be used upfront. Define expected results and behavior, and
tooling requirements before starting to design a GraphQL API.
JavaScript
Copy
For example, if row or field level authorization of data is required in the API, the decision must be known to
make the correct decisions about tooling. For some scenarios, using Amazon Cognito might be perfect,
for others, perhaps just a simple authentication mechanism, and for others still, something completely
different might be needed. Deciding on this up front ensures that the right tooling choices are made and
that project restarts are minimized.
5. Queries
Ensure that only the fields being requested are being queried for, and that they only return what is asked
for. Get Started for Free Contact Us
For example, if the query reads like the following, then it is only asking for field1 and field2 of theEntity to
be returned.
JavaScript
1 query anExtremelyMinimalQuery {
2 theEntity {
3 field1
4 field2
5 }
6 }
Copy
If the database must pull data from a singular table, then the SQL query would look something like the
following:
JavaScript
Copy
JavaScript
Copy
In these cases, these queries must be generated or written to only include the needed elements for the
GraphQL query. Furthermore, they are written or generated in a way that would be performant. Not doing
so can lead to performance issues.
How to build GraphQL resolvers with managed GraphQL
servers
Get Started for Free Contact Us
Unlike self-hosted open source GraphQL options such as Apollo Server, managed GraphQL solutions
provide a way to shift many operational concerns, and reorient efforts toward organizational use cases.
With a managed GraphQL API service like AWS AppSync, the infrastructure, patching, scaling, availability,
scalability, and other operational activities are managed by AWS.
AWS AppSync provides a serverless GraphQL API service with optimized resolvers to connect to AWS data
sources, compute, and others.
For more information on VTL use in AWS AppSync, see the Resolver Mapping Template Programming
Guide.
If multiple operations need to be executed against one of multiple data sources in a single client request,
the Unit Resolver has to change to a Pipeline Resolver. These Pipeline Resolver operations are executed in
order against selected data source(s). Furthermore, functions can be created to execute during these
operations. This opens up a wide range of sequential operational options during the execution of
esolvers. For further information, see the Pipeline Resolvers Tutorial.
JavaScript
1 #set($id=$utils.autoId())
2 {
3 "version": "2018-05-29",
4 "statements": [
5 "insert into Pets VALUES ('$id', '$ctx.args.input.type', $ct
6 "select * from Pets WHERE id = '$id'"
7 ]
8 }
Then, for the response mapping template, the following code would complete the resolver:
JavaScript
1 $utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
Copy
For an example of connecting resolvers to Aurora Serverless options, see this Aurora Serverless Tutorial.
This Lambda Resolvers Tutorial demonstrates the power of building GraphQL resolvers for AWS AppSync
with Lambda functions. The switch is used to handle one of several types of actions in the Lambda for
each of the AWS AppSync resolvers.
JavaScript
Copy
Once that Lambda is available, then the resolver VTL would make calls that are minimal to pass in the
event, context, and related parameters. The request mapping template would look like the following:
JavaScript
1 {
2 "version": "2017-02-28",
3 "operation": "Invoke",
4 "payload": {
5 "field": "getPost",
6 "arguments": $utils.toJson($context.arguments)
7 }
8 }
Copy
JavaScript
1 $utils.toJson($context.result)
Copy
Best practices for building resolvers with managed GraphQL AppSync
1. ResolverGet Started
level for Free
caching Contact Us
Turning on per-resolver caching provides resolver specific settings for arguments, source, and identity
maps on which to base the cache hits. This provides another level of caching beyond full request caching
that lets each resolver cache based on its specific data requests to
servers.
A popular capability to pair with GraphQL APIs is the ability to issue an HTTP action as a request, and then
build the response based on that action call. A HTTP Resolver can be used to accomplish this task based
on API needs. This can provide a means to connect to other APIs via whichever mechanism, such as
GraphQL, REST, or other options.
If a particular language or functionality is needed for an API, using Lambda resolvers introduces the option
for different support languages to connect with any type of data source. These include Amazon RDS and
Postgres or Aurora, and it will work with those results as needed. For more information, see Introducing
Direct Lambda Resolvers: AWS AppSync GraphQL APIs without VTL.
To try AWS AppSync with little coding, AWS Amplify Studio or AWS Amplify CLI tooling are good options
are they auto-generate GraphQL APIs. This includes all VTL resolver code based on a schema. Additional
tooling with Amplify Studio provides a way to build out a schema graphically. Furthermore, it can draw
relationships with immediate schema and the ability to deploy the API with fully functional resolvers built.
There are many authentication options with AWS AppSync, including Amazon Cognito, OIDC, IAM, and API
Keys. Moreover, if a custom authentication option is needed, using Lambda Resolvers provides this option
to connect and authenticate, or authorize data consumers against the API.
Category Self-hosted, open source GraphQL AWS AppSync managed GraphQL service
servers
Configuration Many of the secrets for connection, Secrets are managed across
Get Started for Free Contact Us
configuration of databases, and other environments and require minimal
criteria must be managed. This interaction from the developer. These
requires a secrets vault or other data sources in an AWS AppSync API are
system of keeping secrets, and all seamlessly integrated and the
configurations managed across developer can focus more on the model
environments. and organizational use case.
Data Full control over the exact response Control of the request and response
and request of data inbound and cycles with various tooling, and
outbound from the database. immediacy of generated query calls into
However, each function can become a the database. This provides a boost
costly development process. toward focusing on organizational use
cases.
Developer Can provide the most extensive Provides a faster on-ramp for the
flexibility around implementing code, deployment of GraphQL APIs, and
database, and models for GraphQL streamlines process. However, it will be
APIs. limited if more elaborate and complex
coding is needed.
Cost Introduces a range of additional costs, Provides a singular line item based on
including servers, functions, individual usage only.
resources, possible additional staff,
and others.
Looking for a fully managed GraphQL service?