Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(appsync): support appsync functions for pipelineConfig #10111

Merged
merged 37 commits into from
Dec 7, 2020
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f3c77e3
refactor(appsync): graphQLApi to graphqlApi for better snakecasing
BryanPan342 Aug 31, 2020
51edc01
Revert "refactor(appsync): graphQLApi to graphqlApi for better snakec…
BryanPan342 Aug 31, 2020
884e185
Merge remote-tracking branch 'upstream/master'
BryanPan342 Aug 31, 2020
9ad9d36
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 1, 2020
d9ebafb
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 1, 2020
64db87e
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 1, 2020
7979214
logic complete for appsync functions
BryanPan342 Sep 1, 2020
b3622b0
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 1, 2020
c0acf8a
Merge branch 'master' into appsync-functions
BryanPan342 Sep 2, 2020
a2ab789
update current changes
BryanPan342 Sep 2, 2020
4cdd244
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 2, 2020
0ea712f
add to readme
BryanPan342 Sep 2, 2020
6608704
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 3, 2020
f85ce81
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 4, 2020
e8cfc0c
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 8, 2020
1423bc6
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 8, 2020
6c9bee1
Merge branch 'master' into appsync-functions
BryanPan342 Sep 8, 2020
2ea72ed
Merge remote-tracking branch 'upstream/master'
BryanPan342 Sep 8, 2020
18207f0
Merge branch 'master' into appsync-functions
BryanPan342 Sep 8, 2020
4a12a90
change appsync-functions to no longer take functionVersion
BryanPan342 Sep 8, 2020
3490b7e
Merge branch 'appsync-functions' of https://github.com/BryanPan342/aw…
BryanPan342 Sep 8, 2020
29e0932
this breaks but look at the _bindXxx function in schema-intermediate
BryanPan342 Sep 10, 2020
828ed60
jank fix
BryanPan342 Sep 10, 2020
8844b8e
clean up work
BryanPan342 Sep 10, 2020
0337396
Merge branch 'master' into appsync-functions
BryanPan342 Oct 2, 2020
987cb1c
changes
BryanPan342 Oct 2, 2020
987427f
build fixes
BryanPan342 Oct 2, 2020
9af884b
lint
BryanPan342 Oct 2, 2020
deab28f
Merge branch 'master' into appsync-functions
BryanPan342 Oct 2, 2020
9123f75
remove merge artifact
BryanPan342 Oct 2, 2020
8797393
merge artifact
BryanPan342 Oct 2, 2020
7e4c3fe
revert to master
BryanPan342 Nov 2, 2020
06d2964
Merge branch 'master' into appsync-functions
BryanPan342 Dec 7, 2020
a9affbd
Merge branch 'appsync-functions' of https://github.com/bryanpan342/aw…
BryanPan342 Dec 7, 2020
c4e6307
run integ
BryanPan342 Dec 7, 2020
18b1ebc
Merge branch 'master' into appsync-functions
BryanPan342 Dec 7, 2020
66289b2
Merge branch 'master' into appsync-functions
mergify[bot] Dec 7, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 35 additions & 3 deletions packages/@aws-cdk/aws-appsync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,38 @@ api.grantMutation(role, 'updateExample');
api.grant(role, appsync.IamResource.ofType('Mutation', 'updateExample'), 'appsync:GraphQL');
```

### Pipeline Resolvers and AppSync Functions

AppSync Functions are local functions that perform certain operations onto a
backend data source. Developers can compose operations (Functions) and execute
them in sequence with Pipeline Resolvers.

```ts
const appsyncFunction = new appsync.AppsyncFunction(stack, 'function', {
name: 'appsync_function',
api: api,
dataSource: apiDataSource,
requestMappingTemplate: appsync.MappingTemplate.fromFile('request.vtl'),
responseMappingTemplate: appsync.MappingTemplate.fromFile('response.vtl'),
});
```

AppSync Functions are used in tandem with pipeline resolvers to compose multiple
operations.

```ts
const pipelineResolver = new appsync.Resolver(stack, 'pipeline', {
name: 'pipeline_resolver',
api: api,
dataSource: apiDataSource,
requestMappingTemplate: appsync.MappingTemplate.fromFile('beforeRequest.vtl'),
pipelineConfig: [appsyncFunction],
responseMappingTemplate: appsync.MappingTemplate.fromFile('afterResponse.vtl'),
});
```

Learn more about Pipeline Resolvers and AppSync Functions [here](https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html).

### Code-First Schema

CDK offers the ability to generate your schema in a code-first approach.
Expand Down Expand Up @@ -465,7 +497,7 @@ To learn more about authorization and directives, read these docs [here](https:/
While `GraphqlType` is a base implementation for GraphQL fields, we have abstractions
on top of `GraphqlType` that provide finer grain support.

##### Field
#### Field

`Field` extends `GraphqlType` and will allow you to define arguments. [**Interface Types**](#Interface-Types) are not resolvable and this class will allow you to define arguments,
but not its resolvers.
Expand All @@ -492,7 +524,7 @@ const type = new appsync.InterfaceType('Node', {
});
```

##### Resolvable Fields
#### Resolvable Fields

`ResolvableField` extends `Field` and will allow you to define arguments and its resolvers.
[**Object Types**](#Object-Types) can have fields that resolve and perform operations on
Expand Down Expand Up @@ -567,7 +599,7 @@ Intermediate Types include:
- [**Input Types**](#Input-Types)
- [**Union Types**](#Union-Types)

##### Interface Types
#### Interface Types

**Interface Types** are abstract types that define the implementation of other
intermediate types. They are useful for eliminating duplication and can be used
Expand Down
148 changes: 148 additions & 0 deletions packages/@aws-cdk/aws-appsync/lib/appsync-function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { Resource, IResource, Lazy, Fn } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnFunctionConfiguration } from './appsync.generated';
import { BaseDataSource } from './data-source';
import { IGraphqlApi } from './graphqlapi-base';
import { MappingTemplate } from './mapping-template';

/**
* the base properties for AppSync Functions
*/
export interface BaseAppsyncFunctionProps {
/**
* the name of the AppSync Function
*/
readonly name: string;
/**
* the description for this AppSync Function
*
* @default - no description
*/
readonly description?: string;
/**
* the request mapping template for the AppSync Function
*
* @default - no request mapping template
*/
readonly requestMappingTemplate?: MappingTemplate;
/**
* the response mapping template for the AppSync Function
*
* @default - no response mapping template
*/
readonly responseMappingTemplate?: MappingTemplate;
}

/**
* the CDK properties for AppSync Functions
*/
export interface AppsyncFunctionProps extends BaseAppsyncFunctionProps {
/**
* the GraphQL Api linked to this AppSync Function
*/
readonly api: IGraphqlApi;
/**
* the data source linked to this AppSync Function
*/
readonly dataSource: BaseDataSource;
}

/**
* The attributes for imported AppSync Functions
*/
export interface AppsyncFunctionAttributes {
/**
* the ARN of the AppSync function
*/
readonly functionArn: string;
}

/**
* Interface for AppSync Functions
*/
export interface IAppsyncFunction extends IResource {
/**
* the name of this AppSync Function
*
* @attribute
*/
readonly functionId: string;
/**
* the ARN of the AppSync function
*
* @attribute
*/
readonly functionArn: string;
}

/**
* AppSync Functions are local functions that perform certain operations
* onto a backend data source. Developers can compose operations (Functions)
* and execute them in sequence with Pipeline Resolvers.
*
* @resource AWS::AppSync::FunctionConfiguration
*/
export class AppsyncFunction extends Resource implements IAppsyncFunction {
/**
* Import Appsync Function from arn
*/
public static fromAppsyncFunctionAttributes(scope: Construct, id: string, attrs: AppsyncFunctionAttributes): IAppsyncFunction {
class Import extends Resource {
public readonly functionId = Lazy.stringValue({
produce: () => Fn.select(3, Fn.split('/', attrs.functionArn)),
});
public readonly functionArn = attrs.functionArn;
constructor (s: Construct, i: string) {
super(s, i);
}
}
return new Import(scope, id);
}

/**
* the name of this AppSync Function
*
* @attribute Name
*/
public readonly functionName: string;
/**
* the ARN of the AppSync function
*
* @attribute
*/
public readonly functionArn: string;
/**
* the ID of the AppSync function
*
* @attribute
*/
public readonly functionId: string;
/**
* the data source of this AppSync Function
*
* @attribute DataSourceName
*/
public readonly dataSource: BaseDataSource;

private readonly function: CfnFunctionConfiguration;

public constructor(scope: Construct, id: string, props: AppsyncFunctionProps) {
super(scope, id);
this.function = new CfnFunctionConfiguration(this, 'Resource', {
name: props.name,
description: props.description,
apiId: props.api.apiId,
dataSourceName: props.dataSource.name,
functionVersion: '2018-05-29',
requestMappingTemplate: props.requestMappingTemplate?.renderTemplate(),
responseMappingTemplate: props.responseMappingTemplate?.renderTemplate(),
});
this.functionName = this.function.attrName;
this.functionArn = this.function.attrFunctionArn;
this.functionId = this.function.attrFunctionId;
this.dataSource = props.dataSource;

this.function.addDependsOn(this.dataSource.ds);
props.api.addSchemaDependency(this.function);
}
}
11 changes: 9 additions & 2 deletions packages/@aws-cdk/aws-appsync/lib/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IGrantable, IPrincipal, IRole, Role, ServicePrincipal } from '@aws-cdk/
import { IFunction } from '@aws-cdk/aws-lambda';
import { IResolvable } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { BaseAppsyncFunctionProps, AppsyncFunction } from './appsync-function';
import { CfnDataSource } from './appsync.generated';
import { IGraphqlApi } from './graphqlapi-base';
import { BaseResolverProps, Resolver } from './resolver';
Expand Down Expand Up @@ -123,7 +124,14 @@ export abstract class BaseDataSource extends CoreConstruct {
* creates a new resolver for this datasource and API using the given properties
*/
public createResolver(props: BaseResolverProps): Resolver {
return new Resolver(this, `${props.typeName}${props.fieldName}Resolver`, {
return this.api.createResolver({ dataSource: this, ...props });
}

/**
* creates a new appsync function for this datasource and API using the given properties
*/
public createFunction(props: BaseAppsyncFunctionProps): AppsyncFunction {
return new AppsyncFunction(this, `${props.name}Function`, {
api: this.api,
dataSource: this,
...props,
Expand Down Expand Up @@ -170,7 +178,6 @@ export class NoneDataSource extends BaseDataSource {
export interface DynamoDbDataSourceProps extends BackedDataSourceProps {
/**
* The DynamoDB table backing this data source
* [disable-awslint:ref-via-interface]
*/
readonly table: ITable;
/**
Expand Down
18 changes: 17 additions & 1 deletion packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
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, AwsIamConfig } from './data-source';
import { AwsIamConfig, DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource } from './data-source';
import { Resolver, ExtendedResolverProps } from './resolver';

/**
* Optional configuration for data sources
Expand Down Expand Up @@ -90,6 +91,11 @@ export interface IGraphqlApi extends IResource {
*/
addLambdaDataSource(id: string, lambdaFunction: IFunction, options?: DataSourceOptions): LambdaDataSource;

/**
* creates a new resolver for this datasource and API using the given properties
*/
createResolver(props: ExtendedResolverProps): Resolver;

/**
* Add schema dependency if not imported
*
Expand Down Expand Up @@ -178,6 +184,16 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
});
}

/**
* creates a new resolver for this datasource and API using the given properties
*/
public createResolver(props: ExtendedResolverProps): Resolver {
return new Resolver(this, `${props.typeName}${props.fieldName}Resolver`, {
api: this,
...props,
});
}

/**
* Add schema dependency if not imported
*
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-appsync/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// AWS::AppSync CloudFormation Resources:
export * from './appsync-function';
export * from './appsync.generated';
export * from './key';
export * from './data-source';
Expand Down
29 changes: 21 additions & 8 deletions packages/@aws-cdk/aws-appsync/lib/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Construct } from 'constructs';
import { IAppsyncFunction } from './appsync-function';
import { CfnResolver } from './appsync.generated';
import { BaseDataSource } from './data-source';
import { IGraphqlApi } from './graphqlapi-base';
Expand Down Expand Up @@ -26,7 +27,7 @@ export interface BaseResolverProps {
* @default - no pipeline resolver configuration
* An empty array | undefined sets resolver to be of kind, unit
*/
readonly pipelineConfig?: string[];
readonly pipelineConfig?: IAppsyncFunction[];
/**
* The request mapping template for this resolver
*
Expand All @@ -42,13 +43,9 @@ export interface BaseResolverProps {
}

/**
* Additional properties for an AppSync resolver like GraphQL API reference and datasource
* Additional property for an AppSync resolver for data source reference
*/
export interface ResolverProps extends BaseResolverProps {
/**
* The API this resolver is attached to
*/
readonly api: IGraphqlApi;
export interface ExtendedResolverProps extends BaseResolverProps {
/**
* The data source this resolver is using
*
Expand All @@ -57,6 +54,16 @@ export interface ResolverProps extends BaseResolverProps {
readonly dataSource?: BaseDataSource;
}

/**
* Additional property for an AppSync resolver for GraphQL API reference
*/
export interface ResolverProps extends ExtendedResolverProps {
/**
* The API this resolver is attached to
*/
readonly api: IGraphqlApi;
}

/**
* An AppSync resolver
*/
Expand All @@ -71,7 +78,13 @@ export class Resolver extends CoreConstruct {
constructor(scope: Construct, id: string, props: ResolverProps) {
super(scope, id);

const pipelineConfig = props.pipelineConfig && props.pipelineConfig.length ? { functions: props.pipelineConfig } : undefined;
const pipelineConfig = props.pipelineConfig && props.pipelineConfig.length ?
{ functions: props.pipelineConfig.map((func) => func.functionId) }
: undefined;

if (pipelineConfig && props.dataSource) {
throw new Error(`Pipeline Resolver cannot have data source. Received: ${props.dataSource.name}`);
}

this.resolver = new CfnResolver(this, 'Resource', {
apiId: props.api.apiId,
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-appsync/lib/schema-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export interface IIntermediateType {
/**
* Method called when the stringifying Intermediate Types for schema generation
*
* @param api The binding GraphQL Api [disable-awslint:ref-via-interface]
* @param api The binding GraphQL Api
*
* @internal
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-appsync/lib/schema-field.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IAppsyncFunction } from './appsync-function';
import { BaseDataSource } from './data-source';
import { AuthorizationType } from './graphqlapi';
import { MappingTemplate } from './mapping-template';
Expand Down Expand Up @@ -423,7 +424,7 @@ export interface ResolvableFieldOptions extends FieldOptions {
* @default - no pipeline resolver configuration
* An empty array or undefined prop will set resolver to be of type unit
*/
readonly pipelineConfig?: string[];
readonly pipelineConfig?: IAppsyncFunction[];
/**
* The request mapping template for this resolver
*
Expand Down
Loading