Skip to content

Instantly share code, notes, and snippets.

@wulfmann
Last active January 23, 2022 11:33
Show Gist options
  • Save wulfmann/82649af0d9fa7a0049ff8dd1440291e4 to your computer and use it in GitHub Desktop.
Save wulfmann/82649af0d9fa7a0049ff8dd1440291e4 to your computer and use it in GitHub Desktop.
How to get an S3 object from an AppSync Resolver using Apache Velocity Templates
import * as cdk from '@aws-cdk/aws-cdk';
import * as appsync from '@aws-cdk/aws-appsync';
import * as s3 from '@aws-cdk/aws-s3';
// Our new S3 Data Source Construct
import { S3DataSource } from './s3-data-source.ts';
/**
* This file contains a sample CDK Stack that creates:
* - A new appsync graphql api
* - An S3 Bucket
* - An S3 Data Source
* - A resolver for the `content` field on the `S3Object` type
*/
const app = new cdk.App();
const stack = new cdk.Stack(app, `example-stack`);
const api = new appsync.GraphqlApi(stack, `Api`, {
schema: appsync.Schema.fromAsset('schema.graphql')
});
const bucket = new s3.Bucket(stack, `Bucket`);
// You must pass a role with permission to perform the S3 actions in your bucket
const serviceRole = new iam.Role(stack, `S3SourceServiceRole`, {
assumedBy: new iam.ServicePrincipal('appsync.amazonaws.com')
})
bucket.grantRead(serviceRole);
const s3Source = new S3DataSource(stack, `S3Source`, {
bucket,
api,
serviceRole
});
s3Source.createResolver({
typeName: 'S3Object',
fieldName: 'content',
requestMappingTemplate: appsync.MappingTemplate.fromFile('request.vtl'),
responseMappingTemplate: appsync.MappingTemplate.fromFile('response.vtl')
});
{
"version": "2018-05-29",
"method": "GET",
"resourcePath": "$context.arguments.key"
}
#if($context.result.statusCode && $context.result.statusCode != 200)
#set ($error = $utils.xml.toMap($context.result.body))Error
$utils.error($error.Message, $error.Code, $context.result, $error)
#else
$util.toJson($context.result.body)
#end
import * as cdk from '@aws-cdk/aws-cdk';
import * as appsync from '@aws-cdk/aws-appsync';
import * as s3 from '@aws-cdk/aws-s3';
/**
* This file contains a `BackedDataSource` implementation for interacting with S3.
* It creates an HTTP AppSync Data Source.
*/
export interface S3DataSourceProps extends appsync.BackedDataSourceProps {
bucket: s3.IBucket;
}
export class S3DataSource extends appsync.BackedDataSource {
constructor(scope: cdk.Construct, id: string, props: S3DataSourceProps) {
super(scope, id, props, {
type: 'HTTP',
httpConfig: {
endpoint: `https://${props.bucket.bucketRegionalDomainName}`,
authorizationConfig: {
authorizationType: 'AWS_IAM',
awsIamConfig: {
signingRegion: 'us-east-1', // this can be whatever region you are deploying into
signingServiceName: 's3'
}
}
}
})
}
}
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>NoSuchKey</Code>
<Message>The resource you requested does not exist</Message>
<Resource>/mybucket/myfoto.jpg</Resource>
<RequestId>4442587FB7D0A2F9</RequestId>
</Error>
query MyQuery {
getObjectByKey(key: "/mybucket/myfoto.jpg") {
content
}
}
{
"data": {
"content": null
},
"errors": [
{
"path": [
"getObjectByKey",
"content"
],
"data": null,
"errorType": "NoSuchKey",
"errorInfo": {
"Message": "The specified key does not exist.",
"RequestId": "4442587FB7D0A2F9",
"HostId": "",
"Code": "NoSuchKey",
"Key": "/mybucket/myfoto.jpg"
},
"locations": [
{
"line": 0,
"column": 0,
"sourceName": null
}
],
"message": "The specified key does not exist."
}
]
}
type S3Object {
key: String
content: String
}
type Query {
getObjectByKey(key: String!): String
}
@wulfmann
Copy link
Author

wulfmann commented Nov 6, 2020

This gist contains a number of files that gives a solution for fetching S3 objects directly from a graphql resolver using apache velocity templates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment