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): add authorization config to the HttpDataSource #10171

Merged
82 changes: 80 additions & 2 deletions packages/@aws-cdk/aws-appsync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:

Expand Down Expand Up @@ -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": "<your step functions arn>",
"input": "{ \"id\": \"$context.arguments.id\" }"
}
}
}
```

GraphQL response 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, 'api', {
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`
Expand Down Expand Up @@ -129,7 +208,6 @@ const api = appsync.GraphqlApi(stack, 'api', {
```

### 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.
Expand Down
30 changes: 29 additions & 1 deletion packages/@aws-cdk/aws-appsync/lib/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -211,18 +226,31 @@ 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;
}

/**
* An AppSync datasource backed by a http endpoint
*/
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',
});
}
}
Expand Down
19 changes: 16 additions & 3 deletions packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
*/
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
});
}

Expand Down
30 changes: 29 additions & 1 deletion packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand Down Expand Up @@ -97,4 +126,3 @@ describe('adding http data source from imported api', () => {
});
});