-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
resolver.ts
165 lines (149 loc) · 5.12 KB
/
resolver.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import { Construct } from 'constructs';
import { IAppsyncFunction } from './appsync-function';
import { CfnResolver } from './appsync.generated';
import { CachingConfig } from './caching-config';
import { BASE_CACHING_KEYS } from './caching-key';
import { Code } from './code';
import { BaseDataSource } from './data-source';
import { IGraphqlApi } from './graphqlapi-base';
import { MappingTemplate } from './mapping-template';
import { FunctionRuntime } from './runtime';
import { Token } from '../../core';
/**
* Basic properties for an AppSync resolver
*/
export interface BaseResolverProps {
/**
* name of the GraphQL type this resolver is attached to
*/
readonly typeName: string;
/**
* name of the GraphQL field in the given type this resolver is attached to
*/
readonly fieldName: string;
/**
* configuration of the pipeline resolver
*
* @default - no pipeline resolver configuration
* An empty array | undefined sets resolver to be of kind, unit
*/
readonly pipelineConfig?: IAppsyncFunction[];
/**
* The request mapping template for this resolver
*
* @default - No mapping template
*/
readonly requestMappingTemplate?: MappingTemplate;
/**
* The response mapping template for this resolver
*
* @default - No mapping template
*/
readonly responseMappingTemplate?: MappingTemplate;
/**
* The caching configuration for this resolver
*
* @default - No caching configuration
*/
readonly cachingConfig?: CachingConfig;
/**
* The maximum number of elements per batch, when using batch invoke
*
* @default - No max batch size
*/
readonly maxBatchSize?: number;
/**
* The functions runtime
*
* @default - no function runtime, VTL mapping templates used
*/
readonly runtime?: FunctionRuntime;
/**
* The function code
*
* @default - no code is used
*/
readonly code?: Code;
}
/**
* Additional property for an AppSync resolver for data source reference
*/
export interface ExtendedResolverProps extends BaseResolverProps {
/**
* The data source this resolver is using
*
* @default - No datasource
*/
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
*/
export class Resolver extends Construct {
/**
* the ARN of the resolver
*/
public readonly arn: string;
private resolver: CfnResolver;
constructor(scope: Construct, id: string, props: ResolverProps) {
super(scope, id);
const pipelineConfig = props.pipelineConfig && props.pipelineConfig.length ?
{ functions: props.pipelineConfig.map((func) => func.functionId) }
: undefined;
// If runtime is specified, code must also be
if (props.runtime && !props.code) {
throw new Error('Code is required when specifying a runtime');
}
if (props.code && (props.requestMappingTemplate || props.responseMappingTemplate)) {
throw new Error('Mapping templates cannot be used alongside code');
}
if (pipelineConfig && props.dataSource) {
throw new Error(`Pipeline Resolver cannot have data source. Received: ${props.dataSource.name}`);
}
if (props.cachingConfig?.ttl && (props.cachingConfig.ttl.toSeconds() < 1 || props.cachingConfig.ttl.toSeconds() > 3600)) {
throw new Error(`Caching config TTL must be between 1 and 3600 seconds. Received: ${props.cachingConfig.ttl.toSeconds()}`);
}
if (props.cachingConfig?.cachingKeys) {
if (props.cachingConfig.cachingKeys.find(cachingKey =>
!Token.isUnresolved(cachingKey) && !BASE_CACHING_KEYS.find(baseCachingKey => cachingKey.startsWith(baseCachingKey)))) {
throw new Error(`Caching config keys must begin with $context.arguments, $context.source or $context.identity. Received: ${props.cachingConfig.cachingKeys}`);
}
}
const code = props.code?.bind(this);
this.resolver = new CfnResolver(this, 'Resource', {
apiId: props.api.apiId,
typeName: props.typeName,
fieldName: props.fieldName,
dataSourceName: props.dataSource ? props.dataSource.name : undefined,
kind: pipelineConfig ? 'PIPELINE' : 'UNIT',
runtime: props.runtime?.toProperties(),
codeS3Location: code?.s3Location,
code: code?.inlineCode,
pipelineConfig: pipelineConfig,
requestMappingTemplate: props.requestMappingTemplate ? props.requestMappingTemplate.renderTemplate() : undefined,
responseMappingTemplate: props.responseMappingTemplate ? props.responseMappingTemplate.renderTemplate() : undefined,
cachingConfig: this.createCachingConfig(props.cachingConfig),
maxBatchSize: props.maxBatchSize,
});
props.api.addSchemaDependency(this.resolver);
if (props.dataSource) {
this.resolver.addDependency(props.dataSource.ds);
}
this.arn = this.resolver.attrResolverArn;
}
private createCachingConfig(config?: CachingConfig) {
return config ? {
cachingKeys: config.cachingKeys,
ttl: config.ttl?.toSeconds(),
} : undefined;
}
}