@aws-amplify/graphql-transformer-core
Version:
A framework to transform from GraphQL SDL to AWS CloudFormation.
231 lines • 11.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GraphQLApi = void 0;
const aws_appsync_1 = require("aws-cdk-lib/aws-appsync");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const cdk = __importStar(require("aws-cdk-lib"));
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_logs_1 = require("aws-cdk-lib/aws-logs");
const schema_asset_1 = require("./cdk-compat/schema-asset");
const transform_host_1 = require("./transform-host");
const utils_1 = require("./utils");
class GraphQLApi extends aws_appsync_1.GraphqlApiBase {
constructor(scope, id, props) {
var _a, _b, _c;
super(scope, id);
this.authorizationConfig = {
defaultAuthorization: { authorizationType: aws_appsync_1.AuthorizationType.API_KEY },
additionalAuthorizationModes: [],
...props.authorizationConfig,
};
const defaultMode = this.authorizationConfig.defaultAuthorization;
const additionalModes = this.authorizationConfig.additionalAuthorizationModes;
const modes = [defaultMode, ...additionalModes];
this.modes = modes.map((mode) => mode.authorizationType);
this.environmentName = props.environmentName;
this.validateAuthorizationProps(modes);
this.api = new aws_appsync_1.CfnGraphQLApi(this, 'Resource', {
name: props.name,
authenticationType: defaultMode.authorizationType,
openIdConnectConfig: this.setupOpenIdConnectConfig(defaultMode.openIdConnectConfig),
userPoolConfig: this.setupUserPoolConfig(defaultMode.userPoolConfig),
lambdaAuthorizerConfig: this.setupLambdaConfig(defaultMode.lambdaAuthorizerConfig),
additionalAuthenticationProviders: this.setupAdditionalAuthorizationModes(additionalModes),
xrayEnabled: props.xrayEnabled,
logConfig: this.setupLogConfig(props.logging),
});
this.apiId = this.api.attrApiId;
this.arn = this.api.attrArn;
this.graphqlUrl = this.api.attrGraphQlUrl;
this.name = this.api.name;
this.graphQLEndpointArn = this.api.attrGraphQlEndpointArn;
this.visibility = this.api.visibility === 'PRIVATE' ? aws_appsync_1.Visibility.PRIVATE : aws_appsync_1.Visibility.GLOBAL;
this.schema = (_a = props.schema) !== null && _a !== void 0 ? _a : new schema_asset_1.TransformerSchema();
this.assetProvider = props.assetProvider;
this.schemaResource = this.schema.bind(this);
const hasApiKey = modes.some((mode) => mode.authorizationType === aws_appsync_1.AuthorizationType.API_KEY);
if (props.createApiKey && hasApiKey) {
const config = (_b = modes.find((mode) => mode.authorizationType === aws_appsync_1.AuthorizationType.API_KEY && mode.apiKeyConfig)) === null || _b === void 0 ? void 0 : _b.apiKeyConfig;
this.apiKeyResource = this.createAPIKey(config);
this.apiKeyResource.addDependency(this.schemaResource);
this.apiKey = this.apiKeyResource.attrApiKey;
}
if (hasApiKey && props.sandboxModeEnabled)
this.sandboxModeEnabled = true;
if (props.disableResolverDeduping)
this.disableResolverDeduping = true;
if (props.host) {
this.host = props.host;
this.host.setAPI(this);
}
else {
this.host = new transform_host_1.DefaultTransformHost({
api: this,
});
}
if (props.logging) {
const defaultRetention = aws_logs_1.RetentionDays.ONE_WEEK;
const retention = props.logging === true ? defaultRetention : (_c = props.logging.retention) !== null && _c !== void 0 ? _c : defaultRetention;
new aws_logs_1.LogRetention(this, 'LogRetention', {
logGroupName: this.getAppSyncLogGroupName(),
retention: retention,
});
}
}
grant(grantee, resources, ...actions) {
return aws_iam_1.Grant.addToPrincipal({
grantee,
actions,
resourceArns: resources.resourceArns(this),
scope: this,
});
}
grantQuery(grantee, ...fields) {
return this.grant(grantee, aws_appsync_1.IamResource.ofType('Query', ...fields), 'appsync:GraphQL');
}
grantMutation(grantee, ...fields) {
return this.grant(grantee, aws_appsync_1.IamResource.ofType('Mutation', ...fields), 'appsync:GraphQL');
}
grantSubscription(grantee, ...fields) {
return this.grant(grantee, aws_appsync_1.IamResource.ofType('Subscription', ...fields), 'appsync:GraphQL');
}
createAPIKey(config) {
var _a, _b;
if (((_a = config === null || config === void 0 ? void 0 : config.expires) === null || _a === void 0 ? void 0 : _a.isBefore(aws_cdk_lib_1.Duration.days(1))) || ((_b = config === null || config === void 0 ? void 0 : config.expires) === null || _b === void 0 ? void 0 : _b.isAfter(aws_cdk_lib_1.Duration.days(365)))) {
throw Error('API key expiration must be between 1 and 365 days.');
}
const expires = (config === null || config === void 0 ? void 0 : config.expires) ? config === null || config === void 0 ? void 0 : config.expires.toEpoch() : undefined;
return new aws_appsync_1.CfnApiKey(this, `${(config === null || config === void 0 ? void 0 : config.name) || 'Default'}ApiKey`, {
expires,
description: (config === null || config === void 0 ? void 0 : config.description) || undefined,
apiId: this.apiId,
});
}
addToSchema(content) {
this.schema.addToSchema(content, '\n');
}
getDefaultAuthorization() {
var _a;
return (_a = this.authorizationConfig) === null || _a === void 0 ? void 0 : _a.defaultAuthorization;
}
validateAuthorizationProps(modes) {
modes.forEach((mode) => {
if (mode.authorizationType === aws_appsync_1.AuthorizationType.OIDC && !mode.openIdConnectConfig) {
throw new Error('Missing default OIDC Configuration');
}
if (mode.authorizationType === aws_appsync_1.AuthorizationType.USER_POOL && !mode.userPoolConfig) {
throw new Error('Missing default OIDC Configuration');
}
});
if (modes.filter((mode) => mode.authorizationType === aws_appsync_1.AuthorizationType.API_KEY).length > 1) {
throw new Error("You can't duplicate API_KEY configuration. See https://docs.aws.amazon.com/appsync/latest/devguide/security.html");
}
if (modes.filter((mode) => mode.authorizationType === aws_appsync_1.AuthorizationType.IAM).length > 1) {
throw new Error("You can't duplicate IAM configuration. See https://docs.aws.amazon.com/appsync/latest/devguide/security.html");
}
}
addSchemaDependency(construct) {
construct.addDependency(this.schemaResource);
return true;
}
setupLogConfig(logging) {
var _a, _b;
if (!logging)
return undefined;
const defaultExcludeVerboseContent = true;
const defaultFieldLogLevel = aws_appsync_1.FieldLogLevel.NONE;
const excludeVerboseContent = logging === true || (typeof logging === 'object' && Object.keys(logging).length === 0)
? defaultExcludeVerboseContent
: (_a = logging.excludeVerboseContent) !== null && _a !== void 0 ? _a : defaultExcludeVerboseContent;
const fieldLogLevel = logging === true || (typeof logging === 'object' && Object.keys(logging).length === 0)
? defaultFieldLogLevel
: (_b = logging.fieldLogLevel) !== null && _b !== void 0 ? _b : defaultFieldLogLevel;
const role = new aws_iam_1.Role(this, 'ApiLogsRole', {
assumedBy: new aws_iam_1.ServicePrincipal('appsync.amazonaws.com'),
managedPolicies: [aws_iam_1.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSAppSyncPushToCloudWatchLogs')],
});
(0, utils_1.setResourceName)(role, { name: 'ApiLogsRole', setOnDefaultChild: true });
return {
cloudWatchLogsRoleArn: role.roleArn,
excludeVerboseContent,
fieldLogLevel,
};
}
setupOpenIdConnectConfig(config) {
if (!config) {
return undefined;
}
return {
authTtl: config.tokenExpiryFromAuth,
clientId: config.clientId,
iatTtl: config.tokenExpiryFromIssue,
issuer: config.oidcProvider,
};
}
setupUserPoolConfig(config) {
if (!config) {
return undefined;
}
return {
userPoolId: config.userPool.userPoolId,
awsRegion: config.userPool.stack.region,
appIdClientRegex: config.appIdClientRegex,
defaultAction: config.defaultAction || aws_appsync_1.UserPoolDefaultAction.ALLOW,
};
}
setupLambdaConfig(config) {
var _a;
if (!config) {
return undefined;
}
return {
authorizerUri: (_a = config.lambdaArn) !== null && _a !== void 0 ? _a : this.lambdaArnKey(config.lambdaFunction),
authorizerResultTtlInSeconds: config.ttlSeconds,
identityValidationExpression: '',
};
}
lambdaArnKey(name) {
return `arn:${cdk.Aws.PARTITION}:lambda:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:function:${name}-${this.environmentName}`;
}
setupAdditionalAuthorizationModes(modes) {
if (!modes || modes.length === 0)
return undefined;
return modes.reduce((acc, mode) => [
...acc,
{
authenticationType: mode.authorizationType,
userPoolConfig: this.setupUserPoolConfig(mode.userPoolConfig),
openIdConnectConfig: this.setupOpenIdConnectConfig(mode.openIdConnectConfig),
lambdaAuthorizerConfig: this.setupLambdaConfig(mode.lambdaAuthorizerConfig),
},
], []);
}
getAppSyncLogGroupName() {
return `/aws/appsync/apis/${this.apiId}`;
}
}
exports.GraphQLApi = GraphQLApi;
//# sourceMappingURL=graphql-api.js.map