Skip to content

Commit 5732b8e

Browse files
authored
feat(appsync): import existing graphql api (#9254)
**[ISSUE]** Appsync missing `fromXxx` functionality, making multiple stack appsync interaction impossible. **[Approach]** Created a base class for  `GraphQLApi` and a `IGraphQLApi` interface for imports. Added `fromXxxAttributes` functions to code base that can add dataSources. **[Notes]** Only accessible props from `IGraphQLApi` are `apiId` and `arn`. Only accessible functions from `IGraphQLApi` are the `addXxxDataSource` functions. Added `props-physical-name:@aws-cdk/aws-appsync.GraphQLApiProps` as linter exception because the breaking change isn't worth the return of making the physical name (name exists already). Added `from-method:@aws-cdk/aws-appsync.GraphQLApi` as linter exception because a `fromGraphQLApiAttributes` function will turn into `from_graph_q_l_api_attributes` in python. Fixes #6959 BREAKING CHANGE: **appsync.addXxxDataSource** `name` and `description` props are now optional and in an `DataSourceOptions` interface. - **appsync**: the props `name` and `description` in `addXxxDataSource` have been moved into new props `options` of type `DataSourceOptions` - **appsync**: `DataSourceOptions.name` defaults to id - **appsync**: `DataSourceOptions.description` defaults to undefined ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 1893a5e commit 5732b8e

18 files changed

+1099
-182
lines changed

packages/@aws-cdk/aws-appsync/README.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const demoTable = new db.Table(stack, 'DemoTable', {
6464
},
6565
});
6666

67-
const demoDS = api.addDynamoDbDataSource('demoDataSource', 'Table for Demos"', demoTable);
67+
const demoDS = api.addDynamoDbDataSource('demoDataSource', demoTable);
6868

6969
// Resolver for the Query "getDemos" that scans the DyanmoDb table and returns the entire list.
7070
demoDS.createResolver({
@@ -83,6 +83,24 @@ demoDS.createResolver({
8383
});
8484
```
8585

86+
## Imports
87+
88+
Any GraphQL Api that has been created outside the stack can be imported from
89+
another stack into your CDK app. Utilizing the `fromXxx` function, you have
90+
the ability to add data sources and resolvers through a `IGraphQLApi` interface.
91+
92+
```ts
93+
const importedApi = appsync.GraphQLApi.fromGraphQLApiAttributes(stack, 'IApi', {
94+
graphqlApiId: api.apiId,
95+
graphqlArn: api.arn,
96+
});
97+
importedApi.addDynamoDbDataSource('TableDataSource', table);
98+
```
99+
100+
If you don't specify `graphqlArn` in `fromXxxAttributes`, CDK will autogenerate
101+
the expected `arn` for the imported api, given the `apiId`. For creating data
102+
sources and resolvers, an `apiId` is sufficient.
103+
86104
## Permissions
87105

88106
When using `AWS_IAM` as the authorization type for GraphQL API, an IAM Role

packages/@aws-cdk/aws-appsync/lib/data-source.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { IGrantable, IPrincipal, IRole, Role, ServicePrincipal } from '@aws-cdk/
33
import { IFunction } from '@aws-cdk/aws-lambda';
44
import { Construct, IResolvable } from '@aws-cdk/core';
55
import { CfnDataSource } from './appsync.generated';
6-
import { GraphQLApi } from './graphqlapi';
6+
import { IGraphqlApi } from './graphqlapi-base';
77
import { BaseResolverProps, Resolver } from './resolver';
88

99
/**
@@ -13,11 +13,13 @@ export interface BaseDataSourceProps {
1313
/**
1414
* The API to attach this data source to
1515
*/
16-
readonly api: GraphQLApi;
16+
readonly api: IGraphqlApi;
1717
/**
1818
* The name of the data source
19+
*
20+
* @default - id of data source
1921
*/
20-
readonly name: string;
22+
readonly name?: string;
2123
/**
2224
* the description of the data source
2325
*
@@ -91,7 +93,7 @@ export abstract class BaseDataSource extends Construct {
9193
*/
9294
public readonly ds: CfnDataSource;
9395

94-
protected api: GraphQLApi;
96+
protected api: IGraphqlApi;
9597
protected serviceRole?: IRole;
9698

9799
constructor(scope: Construct, id: string, props: BackedDataSourceProps, extended: ExtendedDataSourceProps) {
@@ -100,15 +102,15 @@ export abstract class BaseDataSource extends Construct {
100102
if (extended.type !== 'NONE') {
101103
this.serviceRole = props.serviceRole || new Role(this, 'ServiceRole', { assumedBy: new ServicePrincipal('appsync') });
102104
}
103-
105+
const name = props.name ?? id;
104106
this.ds = new CfnDataSource(this, 'Resource', {
105107
apiId: props.api.apiId,
106-
name: props.name,
108+
name: name,
107109
description: props.description,
108110
serviceRoleArn: this.serviceRole?.roleArn,
109111
...extended,
110112
});
111-
this.name = props.name;
113+
this.name = name;
112114
this.api = props.api;
113115
}
114116

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import { ITable } from '@aws-cdk/aws-dynamodb';
2+
import { IFunction } from '@aws-cdk/aws-lambda';
3+
import { CfnResource, IResource, Resource } from '@aws-cdk/core';
4+
import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource } from './data-source';
5+
6+
/**
7+
* Optional configuration for data sources
8+
*/
9+
export interface DataSourceOptions {
10+
/**
11+
* The name of the data source, overrides the id given by cdk
12+
*
13+
* @default - generated by cdk given the id
14+
*/
15+
readonly name?: string;
16+
17+
/**
18+
* The description of the data source
19+
*
20+
* @default - No description
21+
*/
22+
readonly description?: string;
23+
}
24+
25+
/**
26+
* Interface for GraphQL
27+
*/
28+
export interface IGraphqlApi extends IResource {
29+
30+
/**
31+
* an unique AWS AppSync GraphQL API identifier
32+
* i.e. 'lxz775lwdrgcndgz3nurvac7oa'
33+
*
34+
* @attribute
35+
*/
36+
readonly apiId: string;
37+
38+
/**
39+
* the ARN of the API
40+
*
41+
* @attribute
42+
*/
43+
readonly arn: string;
44+
45+
/**
46+
* add a new dummy data source to this API. Useful for pipeline resolvers
47+
* and for backend changes that don't require a data source.
48+
*
49+
* @param id The data source's id
50+
* @param options The optional configuration for this data source
51+
*/
52+
addNoneDataSource(id: string, options?: DataSourceOptions): NoneDataSource;
53+
54+
/**
55+
* add a new DynamoDB data source to this API
56+
*
57+
* @param id The data source's id
58+
* @param table The DynamoDB table backing this data source
59+
* @param options The optional configuration for this data source
60+
*/
61+
addDynamoDbDataSource(id: string, table: ITable, options?: DataSourceOptions): DynamoDbDataSource;
62+
63+
/**
64+
* add a new http data source to this API
65+
*
66+
* @param id The data source's id
67+
* @param endpoint The http endpoint
68+
* @param options The optional configuration for this data source
69+
*/
70+
addHttpDataSource(id: string, endpoint: string, options?: DataSourceOptions): HttpDataSource;
71+
72+
/**
73+
* add a new Lambda data source to this API
74+
*
75+
* @param id The data source's id
76+
* @param lambdaFunction The Lambda function to call to interact with this data source
77+
* @param options The optional configuration for this data source
78+
*/
79+
addLambdaDataSource(id: string, lambdaFunction: IFunction, options?: DataSourceOptions): LambdaDataSource;
80+
81+
/**
82+
* Add schema dependency if not imported
83+
*
84+
* @param construct the dependee
85+
*/
86+
addSchemaDependency(construct: CfnResource): boolean;
87+
}
88+
89+
/**
90+
* Base Class for GraphQL API
91+
*/
92+
export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
93+
94+
/**
95+
* an unique AWS AppSync GraphQL API identifier
96+
* i.e. 'lxz775lwdrgcndgz3nurvac7oa'
97+
*/
98+
public abstract readonly apiId: string;
99+
100+
/**
101+
* the ARN of the API
102+
*/
103+
public abstract readonly arn: string;
104+
105+
/**
106+
* add a new dummy data source to this API. Useful for pipeline resolvers
107+
* and for backend changes that don't require a data source.
108+
*
109+
* @param id The data source's id
110+
* @param options The optional configuration for this data source
111+
*/
112+
public addNoneDataSource(id: string, options?: DataSourceOptions): NoneDataSource {
113+
return new NoneDataSource(this, id, {
114+
api: this,
115+
name: options?.name,
116+
description: options?.description,
117+
});
118+
}
119+
120+
/**
121+
* add a new DynamoDB data source to this API
122+
*
123+
* @param id The data source's id
124+
* @param table The DynamoDB table backing this data source
125+
* @param options The optional configuration for this data source
126+
*/
127+
public addDynamoDbDataSource(id: string, table: ITable, options?: DataSourceOptions): DynamoDbDataSource {
128+
return new DynamoDbDataSource(this, id, {
129+
api: this,
130+
table,
131+
name: options?.name,
132+
description: options?.description,
133+
});
134+
}
135+
136+
/**
137+
* add a new http data source to this API
138+
*
139+
* @param id The data source's id
140+
* @param endpoint The http endpoint
141+
* @param options The optional configuration for this data source
142+
*/
143+
public addHttpDataSource(id: string, endpoint: string, options?: DataSourceOptions): HttpDataSource {
144+
return new HttpDataSource(this, id, {
145+
api: this,
146+
endpoint,
147+
name: options?.name,
148+
description: options?.description,
149+
});
150+
}
151+
152+
/**
153+
* add a new Lambda data source to this API
154+
*
155+
* @param id The data source's id
156+
* @param lambdaFunction The Lambda function to call to interact with this data source
157+
* @param options The optional configuration for this data source
158+
*/
159+
public addLambdaDataSource(id: string, lambdaFunction: IFunction, options?: DataSourceOptions): LambdaDataSource {
160+
return new LambdaDataSource(this, id, {
161+
api: this,
162+
lambdaFunction,
163+
name: options?.name,
164+
description: options?.description,
165+
});
166+
}
167+
168+
/**
169+
* Add schema dependency if not imported
170+
*
171+
* @param construct the dependee
172+
*/
173+
public addSchemaDependency(construct: CfnResource): boolean {
174+
construct;
175+
return false;
176+
}
177+
}

0 commit comments

Comments
 (0)