diff --git a/packages/@aws-cdk/aws-appsync/README.md b/packages/@aws-cdk/aws-appsync/README.md index 5ab39d8ec6375..15eb7f88d3fbf 100644 --- a/packages/@aws-cdk/aws-appsync/README.md +++ b/packages/@aws-cdk/aws-appsync/README.md @@ -18,8 +18,10 @@ APIs that use GraphQL. ### Example +#### DynamoDB + Example of a GraphQL API with `AWS_IAM` authorization resolving into a DynamoDb -backend data source. +backend data source. GraphQL schema file `schema.graphql`: @@ -82,6 +84,83 @@ demoDS.createResolver({ }); ``` +#### HTTP Endpoints +GraphQL schema file `schema.graphql`: + +```gql +type job { + id: String! + version: String! +} + +input DemoInput { + version: String! +} + +type Mutation { + callStepFunction(input: DemoInput!): job +} +``` + +GraphQL request mapping template `request.vtl`: + +``` +{ + "version": "2018-05-29", + "method": "POST", + "resourcePath": "/", + "params": { + "headers": { + "content-type": "application/x-amz-json-1.0", + "x-amz-target":"AWSStepFunctions.StartExecution" + }, + "body": { + "stateMachineArn": "", + "input": "{ \"id\": \"$context.arguments.id\" }" + } + } +} +``` + +GraphQL request mapping template `response.vtl`: + +``` +{ + "id": "${context.result.id}" +} +``` + +CDK stack file `app-stack.ts`: + +```ts +import * as appsync from '@aws-cdk/aws-appsync'; + +const api = new appsync.GraphQLApi(scope, 'id', { + name: 'api', + schema: appsync.Schema.fromFile(join(__dirname, 'schema.graphql)) +}); + +const httpDs = api.addHttpDataSource( + 'ds', + 'https://states.amazonaws.com', + { + name: 'httpDsWithStepF', + description: 'from appsync to StepFunctions Workflow', + authorizationConfig: { + signingRegion: 'us-east-1', + signingServiceName: 'states' + } + } +); + +httpDs.createResolver({ + typeName: 'Mutation', + fieldName: 'callStepFunction', + requestMappingTemplate: MappingTemplate.fromFile('request.vtl'), + responseMappingTemplate: MappingTemplate.fromFile('response.vtl') +}); +``` + ### Schema Every GraphQL Api needs a schema to define the Api. CDK offers `appsync.Schema` @@ -128,8 +207,7 @@ const api = appsync.GraphqlApi(stack, 'api', { }); ``` -### Imports - +## Imports Any GraphQL Api that has been created outside the stack can be imported from another stack into your CDK app. Utilizing the `fromXxx` function, you have the ability to add data sources and resolvers through a `IGraphqlApi` interface. diff --git a/packages/@aws-cdk/aws-appsync/lib/data-source.ts b/packages/@aws-cdk/aws-appsync/lib/data-source.ts index 04c617b12e5d0..46a570d461fe2 100644 --- a/packages/@aws-cdk/aws-appsync/lib/data-source.ts +++ b/packages/@aws-cdk/aws-appsync/lib/data-source.ts @@ -203,6 +203,21 @@ export class DynamoDbDataSource extends BackedDataSource { } } +/** + * The authorization config in case the HTTP endpoint requires authorization + */ +export interface AwsIamConfig { + /** + * The signing region for AWS IAM authorization + */ + readonly signingRegion: string; + + /** + * The signing service name for AWS IAM authorization + */ + readonly signingServiceName: string; +} + /** * Properties for an AppSync http datasource */ @@ -211,6 +226,14 @@ export interface HttpDataSourceProps extends BaseDataSourceProps { * The http endpoint */ readonly endpoint: string; + + /** + * The authorization config in case the HTTP endpoint requires authorization + * + * @default - none + * + */ + readonly authorizationConfig?: AwsIamConfig; } /** @@ -218,11 +241,16 @@ export interface HttpDataSourceProps extends BaseDataSourceProps { */ export class HttpDataSource extends BaseDataSource { constructor(scope: Construct, id: string, props: HttpDataSourceProps) { + const authorizationConfig = props.authorizationConfig ? { + authorizationType: 'AWS_IAM', + awsIamConfig: props.authorizationConfig, + } : undefined; super(scope, id, props, { + type: 'HTTP', httpConfig: { endpoint: props.endpoint, + authorizationConfig, }, - type: 'HTTP', }); } } @@ -250,4 +278,4 @@ export class LambdaDataSource extends BackedDataSource { }); props.lambdaFunction.grantInvoke(this); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts index 2f357c142db91..0525b51340fcd 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts @@ -1,7 +1,7 @@ import { ITable } from '@aws-cdk/aws-dynamodb'; import { IFunction } from '@aws-cdk/aws-lambda'; import { CfnResource, IResource, Resource } from '@aws-cdk/core'; -import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource } from './data-source'; +import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource, AwsIamConfig } from './data-source'; /** * Optional configuration for data sources @@ -22,6 +22,18 @@ export interface DataSourceOptions { readonly description?: string; } +/** + * Optional configuration for Http data sources + */ +export interface HttpDataSourceOptions extends DataSourceOptions { + /** + * The authorization config in case the HTTP endpoint requires authorization + * + * @default - none + */ + readonly authorizationConfig?: AwsIamConfig; +} + /** * Interface for GraphQL */ @@ -67,7 +79,7 @@ export interface IGraphqlApi extends IResource { * @param endpoint The http endpoint * @param options The optional configuration for this data source */ - addHttpDataSource(id: string, endpoint: string, options?: DataSourceOptions): HttpDataSource; + addHttpDataSource(id: string, endpoint: string, options?: HttpDataSourceOptions): HttpDataSource; /** * add a new Lambda data source to this API @@ -140,12 +152,13 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { * @param endpoint The http endpoint * @param options The optional configuration for this data source */ - public addHttpDataSource(id: string, endpoint: string, options?: DataSourceOptions): HttpDataSource { + public addHttpDataSource(id: string, endpoint: string, options?: HttpDataSourceOptions): HttpDataSource { return new HttpDataSource(this, id, { api: this, endpoint, name: options?.name, description: options?.description, + authorizationConfig: options?.authorizationConfig, }); } diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts index 6bc237e0f5c71..ee0599aeb4d5a 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts @@ -57,6 +57,35 @@ describe('Http Data Source configuration', () => { }); }); + test('appsync configures name, authorizationConfig correctly', () => { + // WHEN + api.addHttpDataSource('ds', endpoint, { + name: 'custom', + description: 'custom description', + authorizationConfig: { + signingRegion: 'us-east-1', + signingServiceName: 'states', + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::AppSync::DataSource', { + Type: 'HTTP', + Name: 'custom', + Description: 'custom description', + HttpConfig: { + Endpoint: endpoint, + AuthorizationConfig: { + AuthorizationType: 'AWS_IAM', + AwsIamConfig: { + SigningRegion: 'us-east-1', + SigningServiceName: 'states', + }, + }, + }, + }); + }); + test('appsync errors when creating multiple http data sources with no configuration', () => { // THEN expect(() => {