
Product
Redesigned Repositories Page: A Faster Way to Prioritize Security Risk
Our redesigned Repositories page adds alert severity, filtering, and tabs for faster triage and clearer insights across all your projects.
appsync-resolverscript
Advanced tools
Typed JavaScript abstraction for AWS AppSync resolver templates, supporting AWS CDK and Pulumi.
import { PulumiResolver, sendAppSyncRequest, operations, context } from 'appsync-resolverscript'
new PulumiResolver('getUserResolver', {
apiId: horselingApi.id,
dataSource: databaseDataSource.name,
type: 'Query',
field: 'getUser',
template: sendAppSyncRequest(operations.dynamodb.getItem({ id: context.args.id }))
})
import { sendAppSyncRequest, operations } from 'appsync-resolverscript'
const templateBuilder = operations.dynamodb.getItem(({ context }) => ({ id: context.args.id }))
const { requestTemplate, responseTemplate } = templateBuilder
...is equivalent to...
import { sendAppSyncRequest, vtl } from 'appsync-resolverscript'
const templateBuilder = sendAppSyncRequest(({ context, util }) => ({
operation: 'GetItem',
version: '2017-02-28',
key: {
id: util.dynamodb.toDynamoDBJson(context.args.id)
}
})).then(({ context, util }) => util.toJson(context.result))
const { requestTemplate, responseTemplate } = templateBuilder
...is equivalent to...
import { sendAppSyncRequest, vtl } from 'appsync-resolverscript'
const templateBuilder = sendAppSyncRequest({
operation: 'GetItem',
version: '2017-02-28',
key: {
id: vtl`$util.dynamodb.toDynamoDBJson($context.args.id)`
}
}).then(vtl`$util.toJson($context.result)`)
const { requestTemplate, responseTemplate } = templateBuilder
...is equivalent to...
const requestTemplate = `{
"operation": "GetItem",
"version": "2017-02-28",
"key": {
"id": $util.dynamodb.toDynamoDBJson($context.args.id)
}
}`
const responseTemplate = '$util.toJson($context.result)'
With Yarn:
$ yarn add --dev appsync-resolverscript
Or NPM:
$ npm install appsync-resolverscript --save-dev
Use the sendAppSyncRequest(request)
function to define the request template. E.g.
// Defines: {}
const templateBuilder = sendAppSyncRequest({})
request
can be a primitive or object that will be stringified, a Velocity fragment, or a
function that returns any of the above. Multiple arguments are concatenated. It returns a
builder object that can be used to chain the response template.
Note that if you return a raw string as your template definition, it will be stringified to JSON. E.g.
// Defines: "#return"
sendAppSyncRequest('#return')
From the builder returned by the request, use the then(response)
function to define the response
template, in the same way as the request. Again, the builder is returned for further function
chaining. E.g.
// Defines: {}
templateBuilder.then({})
Defining a response is optional, as it defaults to:
$util.toJson($context.result)
For any value in the request or response definition, you can suspend JSON stringification and
provide raw VTL markup by using the vtl
template literal. E.g.
// Defines: #return
sendAppSyncRequest(vtl`#return`)
Alternatively, use an instance of VelocityFragment
.
You can jump back into JSON by embedding the stringify()
method, but make sure you use the one
from this package - it handles fragments, functions and variables correctly. E.g.
// Defines: #set( $person = { "name": "Bob" })
sendAppSyncRequest(vtl`#set( $person = ${stringify({ name: 'Bob' })})`)
The request or response templates can be defined using a function that returns the template structure. This function gets passed the Velocity context as a parameter, providing access to variables and functions. You can implement any logic you like in the function, but remember, any JavaScript conditional logic or loops are executed at deploy time, not when the template is executed - the template definition is the value returned by the function. E.g.
// If useKey === true, defines : $context.args.key
// If useKey === false, defines : { "id": $context.args.id }
sendAppSyncRequest(() => {
const useKey = // ... get from somewhere.
if (useKey) {
return vtl`$context.args.key`
} else {
return {
id: vtl`$context.args.id`
}
}
})
All of the standard AppSync functions are available via the Velocity context passed to function templates (* this is still WIP). Parameters passed to AppSync functions are stringified to JSON. E.g.
// Defines: $context.util.toJson(1, "two")
sendAppSyncRequest(velocityContext => velocityContext.util.toJson(1, 'two'))
You may want to use object-destructuring on the velocityContext
parameter to make this a little
less verbose, especially if you are calling functions in many places:
// Defines: '$context.util.toJson(1, "two")'
sendAppSyncRequest(({ util }) => util.toJson(1, 'two'))
AppSync functions can also be imported at module scope, which allows you avoid the boilerplate of defining your request or response as a function:
import { sendAppSyncRequest, util } from 'appsync-resolverscript'
// Defines: '$context.util.toJson(1, "two")'
sendAppSyncRequest(util.toJson(1, 'two'))
The standard AppSync context object is available as a context
property on the Velocity context passed
to function templates (* this is still WIP). Sorry, overloading the term context is a bit confusing. E.g.
// Defines: { "id": $context.args.id }
sendAppSyncRequest(velocityContext => {
id: velocityContext.context.args.id
})
or
// Defines: { "id": $context.args.id }
sendAppSyncRequest(({ context }) => ({ id: context.args.id }))
Once you get to an args value or result, you can navigate through to any sub-properties (although the sub-properties are not type-checked, as the TypeScript doesn't know the shape of your args or results). E.g.
// Defines: { "id": $context.args.id }
then(({ context, util }) => util.toJson(context.result.items))
Note that the ctx
abbreviation is not supported.
The AppSync context object can also be imported at module scope, The downside of this approach is
that the context object is a superset of request, response and pipeline function contexts, and so not
all properties are appropriate for all mapping types (e.g. context.result
could be mis-used in a
request). The advantage is that it allows you avoid the boilerplate of defining your request
or response as a function. E.g.
import { sendAppSyncRequest, context } from 'appsync-resolverscript'
// Defines: { "id": $context.args.id }
sendAppSyncRequest({ id: context.args.id })
If you are working in Typescript, AppSync function parameters and return values are typed. So too are the non-dynamic properties from the Velocity context. E.g.
// Typescript errors:
// - defaultIfNullOrEmpty(string, string)
// - $context.identity.claims is an object
// - false is a boolean
sendAppSyncRequest(util.defaultIfNullOrEmpty(context.identity.claims, false))
The default type of a Velocity fragment is AnyType
, which matches any other type. This means that
you don't have to worry about the type of any fragments, although you can choose to type them if
you want to enable the type-checking. E.g.
// Typescript errors:
// - defaultIfNullOrEmpty(string, string)
// - $context.identity.claims is an object
sendAppSyncRequest(util.defaultIfNullOrEmpty(vtl<object>`$context.identity.claims`, '[]'))
The builder returned by sendAppSyncRequest(request)
has requestTemplate
and responseTemplate
properties to get the declared request and response mapping template as Velocity Template Language
markup. E.g.
const templateBuilder = sendAppSyncRequest('myRequest').then('myResponse')
assert.deepEqual('"myRequest"', templateBuilder.requestTemplate)
assert.deepEqual('"myResponse"', templateBuilder.responseTemplate)
Note: you don't generally need to use these properties if you use the CDK or Pulumi-specific classes.
Higher-level abstractions of the AppSync operations are available under operations
. They all
accept functions and VTL markup, and return a mapping definition that can be used in
sendAppSyncRequest()
.
GetItem:
const templateBuilder = sentAppSyncRequest(operations.dynamodb.getItem({ id: context.args.id }))
Pulumi is supported via the PulumiResolver
class. It has the same usage as aws.appsync.Resolver
, but the
requestTemplate
and responseTemplate
properties are replaced with template: ResolverTemplateBuilder
, and
can be used as follows:
new PulumiResolver('getUserResolver', {
apiId: horselingApi.id,
dataSource: databaseDataSource.name,
type: 'Query',
field: 'getUser',
template: sendAppSyncRequest(operations.dynamodb.getItem({ id: context.args.id }))
})
util
functions.util
functions.dynamodb
functions.sendRequest().catch()
.map()
and filter()
on variables.Contributions with unit tests are welcome, but please raise an issue and get feedback before spending any significant effort.
FAQs
Write AWS appsync resolvers in JavaScript.
The npm package appsync-resolverscript receives a total of 1 weekly downloads. As such, appsync-resolverscript popularity was classified as not popular.
We found that appsync-resolverscript demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Our redesigned Repositories page adds alert severity, filtering, and tabs for faster triage and clearer insights across all your projects.
Security News
Multiple deserialization flaws in PyTorch Lightning could allow remote code execution when loading untrusted model files, affecting versions up to 2.4.0.
Security News
NVD now marks all pre-2018 CVEs as "Deferred," signaling it will no longer enrich older vulnerabilities, further eroding trust in its data.