Repository: sid88in/serverless-appsync-plugin
Pull request #628 (2024-02-11 09:39:03)

feat: Add Environment Support


Patch:
diff --git a/doc/general-config.md b/doc/general-config.md
index ff6a19d..8cb9196 100644
--- a/doc/general-config.md
+++ b/doc/general-config.md
@@ -44,7 +44,8 @@ appSync:
 - `dataSources`: See [DataSources](dataSources.md)
 - `resolvers`: See [Resolvers](resolvers.md)
 - `pipelineFunctions`: See [Pipeline functions](pipeline-functions.md)
-- `substitutions`: See [Substitutions](substitutions.md)
+- `substitutions`: See [Substitutions](substitutions.md). Deprecated: Use environment variables.
+- `environment`: A list of environment variables for the API. See [Official Documentation](https://docs.aws.amazon.com/appsync/latest/devguide/environmental-variables.html)
 - `caching`: See [Cacing](caching.md)
 - `waf`: See [Web Application Firefall](WAF.md)
 - `logging`: See [Logging](#Logging)
diff --git a/doc/resolvers.md b/doc/resolvers.md
index 7e3d714..48de245 100644
--- a/doc/resolvers.md
+++ b/doc/resolvers.md
@@ -29,7 +29,7 @@ appSync:
 - `code`: The path of the JavaScript resolver handler file, relative to `serverless.yml`. If not specified, a [minimalistic default](#javascript-vs-vtl) is used.
 - `request`: The path to the VTL request mapping template file, relative to `serverless.yml`.
 - `response`: The path to the VTL response mapping template file, relative to `serverless.yml`.
-- `substitutions`: See [Variable Substitutions](substitutions.md)
+- `substitutions`: See [Variable Substitutions](substitutions.md). Deprecated: Use [environment variables](./general-config.md) instead.
 - `caching`: [See below](#Caching)
 - `sync`: [See SyncConfig](syncConfig.md)
 
diff --git a/doc/substitutions.md b/doc/substitutions.md
index 794953b..f43bc53 100644
--- a/doc/substitutions.md
+++ b/doc/substitutions.md
@@ -1,3 +1,5 @@
+> ⚠️ Substitutions are deprecated. Use [Environment Variables](./general-config.md) instead.
+
 # Substitutions
 
 `Substitutions` is a feature that allows you to replace some variables in your VTL mapping templates or JS resolvers with dynamic values.
@@ -30,27 +32,29 @@ appSync:
 <details open>
   <summary>VTL mapping template</summary>
 
-  ```vtl
-  {
-      "version" : "2018-05-29",
-      "operation" : "BatchPutItem",
-      "tables" : {
-          "${postsTable}": [...]
-      }
-  }
-  ```
+```vtl
+{
+    "version" : "2018-05-29",
+    "operation" : "BatchPutItem",
+    "tables" : {
+        "${postsTable}": [...]
+    }
+}
+```
+
 </details>
 
 <details open>
   <summary>JS Resolvers</summary>
-  
-  ```js
-  const tableName = '#postsTable#';
-  return {
-    operation: "BatchGetItem",
-    tables: {
-      [tableName]: { keys },
-    },
-  };
-  ```
+
+```js
+const tableName = '#postsTable#';
+return {
+  operation: 'BatchGetItem',
+  tables: {
+    [tableName]: { keys },
+  },
+};
+```
+
 </details>
diff --git a/src/resources/Api.ts b/src/resources/Api.ts
index 4a451b0..92a9663 100644
--- a/src/resources/Api.ts
+++ b/src/resources/Api.ts
@@ -76,6 +76,7 @@ export class Api {
         Name: this.config.name,
         XrayEnabled: this.config.xrayEnabled || false,
         Tags: this.getTagsConfig(),
+        EnvironmentVariables: this.config.environment,
       },
     };
 
diff --git a/src/types/common.ts b/src/types/common.ts
index b281563..cc8157b 100644
--- a/src/types/common.ts
+++ b/src/types/common.ts
@@ -128,6 +128,7 @@ export type SyncConfig = {
 } & LambdaConfig;
 
 export type Substitutions = Record<string, string | IntrinsicFunction>;
+export type EnvironmentVariables = Record<string, string | IntrinsicFunction>;
 
 export type DsDynamoDBConfig = {
   type: 'AMAZON_DYNAMODB';
diff --git a/src/types/index.ts b/src/types/index.ts
index 8105630..e52f838 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -15,6 +15,7 @@ import {
   DsOpenSearchConfig,
   DsRelationalDbConfig,
   SyncConfig,
+  EnvironmentVariables,
 } from './common';
 export * from './common';
 
@@ -33,6 +34,7 @@ export type AppSyncConfig = {
     | Record<string, DataSourceConfig>[]
     | Record<string, DataSourceConfig>;
   substitutions?: Substitutions;
+  environment?: EnvironmentVariables;
   xrayEnabled?: boolean;
   logging?: LoggingConfig;
   caching?: CachingConfig;
diff --git a/src/types/plugin.ts b/src/types/plugin.ts
index c6f7016..0b8bf8f 100644
--- a/src/types/plugin.ts
+++ b/src/types/plugin.ts
@@ -15,6 +15,7 @@ import {
   DsEventBridgeConfig,
   DsNone,
   Substitutions,
+  EnvironmentVariables,
 } from './common';
 export * from './common';
 
@@ -29,6 +30,7 @@ export type AppSyncConfig = {
   resolvers: Record<string, ResolverConfig>;
   pipelineFunctions: Record<string, PipelineFunctionConfig>;
   substitutions?: Substitutions;
+  environment?: EnvironmentVariables;
   xrayEnabled?: boolean;
   logging?: LoggingConfig;
   caching?: CachingConfig;
diff --git a/src/validation.ts b/src/validation.ts
index 447787e..4cc292e 100644
--- a/src/validation.ts
+++ b/src/validation.ts
@@ -255,6 +255,14 @@ export const appSyncSchema = {
       required: [],
       errorMessage: 'must be a valid substitutions definition',
     },
+    environment: {
+      type: 'object',
+      additionalProperties: {
+        $ref: '#/definitions/stringOrIntrinsicFunction',
+      },
+      required: [],
+      errorMessage: 'must be a valid environment definition',
+    },
     dataSource: {
       if: { type: 'object' },
       then: { $ref: '#/definitions/dataSourceConfig' },
@@ -687,6 +695,7 @@ export const appSyncSchema = {
     queryDepthLimit: { type: 'integer', minimum: 1, maximum: 75 },
     resolverCountLimit: { type: 'integer', minimum: 1, maximum: 1000 },
     substitutions: { $ref: '#/definitions/substitutions' },
+    environment: { $ref: '#/definitions/environment' },
     waf: {
       type: 'object',
       properties: {


Test patch:
diff --git a/src/__tests__/__snapshots__/api.test.ts.snap b/src/__tests__/__snapshots__/api.test.ts.snap
index 37d4314..000e5ce 100644
--- a/src/__tests__/__snapshots__/api.test.ts.snap
+++ b/src/__tests__/__snapshots__/api.test.ts.snap
@@ -20,6 +20,7 @@ Object {
         },
       ],
       "AuthenticationType": "API_KEY",
+      "EnvironmentVariables": undefined,
       "Name": "MyApi",
       "Tags": Array [
         Object {
@@ -47,6 +48,7 @@ Object {
   "GraphQlApi": Object {
     "Properties": Object {
       "AuthenticationType": "AWS_LAMBDA",
+      "EnvironmentVariables": undefined,
       "LambdaAuthorizerConfig": Object {
         "AuthorizerResultTtlInSeconds": undefined,
         "AuthorizerUri": Object {
diff --git a/src/__tests__/api.test.ts b/src/__tests__/api.test.ts
index 56ea77f..87405c9 100644
--- a/src/__tests__/api.test.ts
+++ b/src/__tests__/api.test.ts
@@ -15,6 +15,7 @@ describe('Api', () => {
           "GraphQlApi": Object {
             "Properties": Object {
               "AuthenticationType": "API_KEY",
+              "EnvironmentVariables": undefined,
               "Name": "MyApi",
               "Tags": Array [
                 Object {
@@ -42,6 +43,7 @@ describe('Api', () => {
           "GraphQlApi": Object {
             "Properties": Object {
               "AuthenticationType": "API_KEY",
+              "EnvironmentVariables": undefined,
               "Name": "MyApi",
               "Tags": Array [
                 Object {
@@ -72,6 +74,7 @@ describe('Api', () => {
           "GraphQlApi": Object {
             "Properties": Object {
               "AuthenticationType": "API_KEY",
+              "EnvironmentVariables": undefined,
               "IntrospectionConfig": "DISABLED",
               "Name": "MyApi",
               "QueryDepthLimit": 10,
@@ -90,6 +93,44 @@ describe('Api', () => {
       `);
     });
 
+    it('should compile the Api Resource with Environments', () => {
+      const api = new Api(
+        given.appSyncConfig({
+          environment: {
+            TABLE_NAME: 'MyTable',
+            OTHER_TABLE: {
+              Ref: 'OtherTable',
+            },
+          },
+        }),
+        plugin,
+      );
+      expect(api.compileEndpoint()).toMatchInlineSnapshot(`
+        Object {
+          "GraphQlApi": Object {
+            "Properties": Object {
+              "AuthenticationType": "API_KEY",
+              "EnvironmentVariables": Object {
+                "OTHER_TABLE": Object {
+                  "Ref": "OtherTable",
+                },
+                "TABLE_NAME": "MyTable",
+              },
+              "Name": "MyApi",
+              "Tags": Array [
+                Object {
+                  "Key": "stage",
+                  "Value": "Dev",
+                },
+              ],
+              "XrayEnabled": false,
+            },
+            "Type": "AWS::AppSync::GraphQLApi",
+          },
+        }
+      `);
+    });
+
     it('should compile the Api Resource with logs enabled', () => {
       const api = new Api(
         given.appSyncConfig({
@@ -106,6 +147,7 @@ describe('Api', () => {
           "GraphQlApi": Object {
             "Properties": Object {
               "AuthenticationType": "API_KEY",
+              "EnvironmentVariables": undefined,
               "LogConfig": Object {
                 "CloudWatchLogsRoleArn": Object {
                   "Fn::GetAtt": Array [
@@ -215,6 +257,7 @@ describe('Api', () => {
                 },
               ],
               "AuthenticationType": "AMAZON_COGNITO_USER_POOLS",
+              "EnvironmentVariables": undefined,
               "Name": "MyApi",
               "Tags": Array [
                 Object {
diff --git a/src/__tests__/validation/__snapshots__/base.test.ts.snap b/src/__tests__/validation/__snapshots__/base.test.ts.snap
index 5ee850e..b2b9d27 100644
--- a/src/__tests__/validation/__snapshots__/base.test.ts.snap
+++ b/src/__tests__/validation/__snapshots__/base.test.ts.snap
@@ -60,6 +60,7 @@ exports[`Valdiation should validate  1`] = `
 /introspection: must be boolean
 /queryDepthLimit: must be integer
 /resolverCountLimit: must be integer
+/environment: must be a valid environment definition
 /esbuild: must be an esbuild config object or false"
 `;
 
diff --git a/src/__tests__/validation/base.test.ts b/src/__tests__/validation/base.test.ts
index e4d1f78..5824bc2 100644
--- a/src/__tests__/validation/base.test.ts
+++ b/src/__tests__/validation/base.test.ts
@@ -12,6 +12,10 @@ describe('Valdiation', () => {
         queryDepthLimit: 10,
         resolverCountLimit: 10,
         xrayEnabled: true,
+        environment: {
+          MY_TABLE: 'my-table',
+          MY_OTHER_TABLE: { Ref: 'MyOtherTable' },
+        },
         tags: {
           foo: 'bar',
         },
@@ -32,6 +36,7 @@ describe('Valdiation', () => {
         xrayEnabled: 'BAR',
         unknownPorp: 'foo',
         esbuild: 'bad',
+        environment: 'Bad',
       });
     }).toThrowErrorMatchingSnapshot();