Skip to content

Commit

Permalink
feat: Data client generation using SSM/S3 to provide the MIS to the r…
Browse files Browse the repository at this point in the history
…untime
  • Loading branch information
stocaaro committed Nov 7, 2024
1 parent f08abe4 commit 767d53c
Show file tree
Hide file tree
Showing 10 changed files with 374 additions and 147 deletions.
414 changes: 281 additions & 133 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions packages/backend-data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"@aws-amplify/backend-output-storage": "^1.1.3",
"@aws-amplify/backend-output-schemas": "^1.4.0",
"@aws-amplify/data-construct": "^1.10.1",
"@aws-amplify/plugin-types": "^1.3.1",
"@aws-amplify/data-schema-types": "^1.2.0"
"@aws-amplify/data-schema-types": "^1.2.0",
"@aws-amplify/graphql-generator": "^0.5.0",
"@aws-amplify/plugin-types": "^1.3.1"
}
}
29 changes: 22 additions & 7 deletions packages/backend-data/src/app_sync_policy_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export class AppSyncPolicyGenerator {
/**
* Initialize with the GraphqlAPI that the policies will be scoped to
*/
constructor(private readonly graphqlApi: IGraphqlApi) {
constructor(
private readonly graphqlApi: IGraphqlApi,
private readonly modelIntrospectionSchemaArn?: string
) {
this.stack = Stack.of(graphqlApi);
}
/**
Expand All @@ -29,13 +32,25 @@ export class AppSyncPolicyGenerator {
.map((action) => actionToTypeMap[action])
// convert Type to resourceName
.map((type) => [this.graphqlApi.arn, 'types', type, '*'].join('/'));
return new Policy(this.stack, `${this.policyPrefix}${this.policyCount++}`, {
statements: [

const statements = [
new PolicyStatement({
actions: ['appsync:GraphQL'],
resources,
}),
];

if (this.modelIntrospectionSchemaArn) {
statements.push(
new PolicyStatement({
actions: ['appsync:GraphQL'],
resources,
}),
],
actions: ['s3:GetObject'],
resources: [this.modelIntrospectionSchemaArn],
})
);
}

return new Policy(this.stack, `${this.policyPrefix}${this.policyCount++}`, {
statements,
});
}
}
Expand Down
38 changes: 36 additions & 2 deletions packages/backend-data/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
TranslationBehavior,
} from '@aws-amplify/data-construct';
import { GraphqlOutput } from '@aws-amplify/backend-output-schemas';
import { generateModelsSync } from '@aws-amplify/graphql-generator';
import * as path from 'path';
import { AmplifyDataError, DataProps } from './types.js';
import {
Expand Down Expand Up @@ -45,6 +46,10 @@ import {
FunctionSchemaAccess,
JsResolver,
} from '@aws-amplify/data-schema-types';
import { Bucket } from 'aws-cdk-lib/aws-s3';
import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';

const modelIntrospectionSchemaKey = 'modelIntrospectionSchema.json';

/**
* Singleton factory for AmplifyGraphqlApi constructs that can be used in Amplify project files.
Expand All @@ -55,6 +60,8 @@ export class DataFactory implements ConstructFactory<AmplifyData> {
// publicly accessible for testing purpose only.
static factoryCount = 0;

readonly provides = 'DataResources';

private generator: ConstructContainerEntryGenerator;

/**
Expand Down Expand Up @@ -231,14 +238,21 @@ class DataGenerator implements ConstructContainerEntryGenerator {
...schemasLambdaFunctions,
});
let amplifyApi = undefined;
let modelIntrospectionSchema: string | undefined = undefined;

const isSandboxDeployment =
scope.node.tryGetContext(CDKContextKey.DEPLOYMENT_TYPE) === 'sandbox';

try {
const combinedSchema = combineCDKSchemas(amplifyGraphqlDefinitions);
modelIntrospectionSchema = generateModelsSync({
schema: combinedSchema.schema,
target: 'introspection',
})['model-introspection.json'];

amplifyApi = new AmplifyData(scope, this.name, {
apiName: this.name,
definition: combineCDKSchemas(amplifyGraphqlDefinitions),
definition: combinedSchema,
authorizationModes,
outputStorageStrategy: this.outputStorageStrategy,
functionNameMap,
Expand All @@ -263,6 +277,21 @@ class DataGenerator implements ConstructContainerEntryGenerator {
);
}

// TODO Any risk that this throws?
const modelIntrospectionSchemaBucket = new Bucket(
scope,
'modelIntrospectionSchemaBucket',
{ enforceSSL: true }
);
new BucketDeployment(scope, 'modelIntrospectionSchemaBucketDeployment', {
// See https://github.com/aws-amplify/amplify-category-api/pull/1939
memoryLimit: 1536,
destinationBucket: modelIntrospectionSchemaBucket,
sources: [
Source.data(modelIntrospectionSchemaKey, modelIntrospectionSchema),
],
});

Tags.of(amplifyApi).add(TagName.FRIENDLY_NAME, this.name);

/**;
Expand All @@ -279,10 +308,15 @@ class DataGenerator implements ConstructContainerEntryGenerator {
ssmEnvironmentEntriesGenerator.generateSsmEnvironmentEntries({
[`${this.name}_GRAPHQL_ENDPOINT`]:
amplifyApi.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl,
[`${this.name}_MODEL_INTROSPECTION_SCHEMA_BUCKET_NAME`]:
modelIntrospectionSchemaBucket.bucketName,
[`${this.name}_MODEL_INTROSPECTION_SCHEMA_KEY`]:
modelIntrospectionSchemaKey,
});

const policyGenerator = new AppSyncPolicyGenerator(
amplifyApi.resources.graphqlApi
amplifyApi.resources.graphqlApi,
`${modelIntrospectionSchemaBucket.bucketArn}/${modelIntrospectionSchemaKey}`
);

schemasFunctionSchemaAccess.forEach((accessDefinition) => {
Expand Down
1 change: 1 addition & 0 deletions packages/backend-function/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type FunctionProps = {
schedule?: FunctionSchedule | FunctionSchedule[];
layers?: Record<string, string>;
bundling?: FunctionBundlingOptions;
generateDataClientConfig?: boolean;
};

// @public (undocumented)
Expand Down
6 changes: 6 additions & 0 deletions packages/backend-function/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
"types": "./lib/index.d.ts",
"import": "./lib/index.js",
"require": "./lib/index.js"
},
"./internal": {
"types": "./lib/internal/index.d.ts",
"import": "./lib/internal/index.js",
"require": "./lib/internal/index.js"
}
},
"main": "lib/index.js",
Expand All @@ -27,6 +32,7 @@
"devDependencies": {
"@aws-amplify/backend-platform-test-stubs": "^0.3.6",
"@aws-amplify/platform-core": "^1.1.0",
"@aws-sdk/client-s3": "^3.624.0",
"@aws-sdk/client-ssm": "^3.624.0",
"aws-sdk": "^2.1550.0",
"uuid": "^9.0.1"
Expand Down
17 changes: 17 additions & 0 deletions packages/backend-function/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { EOL } from 'os';
import * as path from 'path';
import { FunctionEnvironmentTranslator } from './function_env_translator.js';
import { FunctionEnvironmentTypeGenerator } from './function_env_type_generator.js';
import { FunctionClientConfigGenerator } from './function_client_config_generator.js';

Check failure on line 40 in packages/backend-function/src/factory.ts

View workflow job for this annotation

GitHub Actions / build (20)

Cannot find module './function_client_config_generator.js' or its corresponding type declarations.

Check failure on line 40 in packages/backend-function/src/factory.ts

View workflow job for this annotation

GitHub Actions / test_with_baseline_dependencies

Cannot find module './function_client_config_generator.js' or its corresponding type declarations.
import { FunctionLayerArnParser } from './layer_parser.js';
import { convertFunctionSchedulesToRuleSchedules } from './schedule_parser.js';

Expand Down Expand Up @@ -145,6 +146,13 @@ export type FunctionProps = {
* Options for bundling the function code.
*/
bundling?: FunctionBundlingOptions;

/*
* Whether to generate a data client config for the function.
*
* Defaults to false.
*/
generateDataClientConfig?: boolean;
};

export type FunctionBundlingOptions = {
Expand Down Expand Up @@ -177,6 +185,8 @@ class FunctionFactory implements ConstructFactory<AmplifyFunction> {
outputStorageStrategy,
resourceNameValidator,
}: ConstructFactoryGetInstanceProps): AmplifyFunction => {
// TODO this should be conditional on some signal,
// for example that any access to data was granted for this function.
if (!this.generator) {
this.generator = new FunctionGenerator(
this.hydrateDefaults(resourceNameValidator),
Expand All @@ -203,6 +213,7 @@ class FunctionFactory implements ConstructFactory<AmplifyFunction> {
schedule: this.resolveSchedule(),
bundling: this.resolveBundling(),
layers,
generateDataClientConfig: this.props.generateDataClientConfig ?? false,
};
};

Expand Down Expand Up @@ -436,6 +447,12 @@ class AmplifyFunction
// This will be overwritten with the typed file at the end of synthesis
functionEnvironmentTypeGenerator.generateProcessEnvShim();

const functionClientConfigGenerator = new FunctionClientConfigGenerator(id);

if (props.generateDataClientConfig) {
functionClientConfigGenerator.generateClientConfig();
}

let functionLambda: NodejsFunction;
try {
functionLambda = new NodejsFunction(scope, `${id}-lambda`, {
Expand Down
5 changes: 5 additions & 0 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
},
"./types/platform": {
"types": "./lib/types/platform.d.ts"
},
"./internal": {
"types": "./lib/internal/index.d.ts",
"import": "./lib/internal/index.js",
"require": "./lib/internal/index.js"
}
},
"main": "lib/index.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/client-config/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ export type CustomClientConfig = {
export const DEFAULT_CLIENT_CONFIG_VERSION: ClientConfigVersion;

// @public
export const generateClientConfig: <T extends "1" | "1.1" | "1.2" | "1.3" | "0">(backendIdentifier: DeployedBackendIdentifier, version: T, awsClientProvider?: AWSClientProvider<{
export const generateClientConfig: <T extends "1.3" | "1.2" | "1.1" | "1" | "0">(backendIdentifier: DeployedBackendIdentifier, version: T, awsClientProvider?: AWSClientProvider<{
getS3Client: S3Client;
getAmplifyClient: AmplifyClient;
getCloudFormationClient: CloudFormationClient;
Expand Down
4 changes: 2 additions & 2 deletions packages/platform-core/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ export const packageJsonSchema: z.ZodObject<{
type: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"module">, z.ZodLiteral<"commonjs">]>>;
}, "strip", z.ZodTypeAny, {
name?: string | undefined;
type?: "module" | "commonjs" | undefined;
version?: string | undefined;
type?: "module" | "commonjs" | undefined;
}, {
name?: string | undefined;
type?: "module" | "commonjs" | undefined;
version?: string | undefined;
type?: "module" | "commonjs" | undefined;
}>;

// @public
Expand Down

0 comments on commit 767d53c

Please sign in to comment.