Repository: sid88in/serverless-appsync-plugin
Pull request #459 (2022-01-01 13:36:21)

Custom variables


Patch:
diff --git a/src/index.ts b/src/index.ts
index 45ecaa7..229ecc5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -25,6 +25,8 @@ import {
   Serverless,
   Provider,
   Hook,
+  VariablesSourcesDefinition,
+  VariableSourceResolver,
 } from './types/serverless';
 import {
   FilterLogEventsResponse,
@@ -33,6 +35,7 @@ import {
 import { AppSyncValidationError, validateConfig } from './validation';
 import { logger, parseDateTimeOrDuration, wait } from './utils';
 import { Api } from './resources/Api';
+import { Naming } from './resources/Naming';
 
 const CONSOLE_BASE_URL = 'https://console.aws.amazon.com';
 
@@ -51,6 +54,7 @@ class ServerlessAppsyncPlugin {
   };
   public readonly hooks: Record<string, Hook>;
   public readonly commands?: CommandsDefinition;
+  public readonly configurationVariablesSources?: VariablesSourcesDefinition;
   private log: ServerlessLogger;
   private writeText: (text: string) => void;
   private api?: Api;
@@ -86,6 +90,12 @@ class ServerlessAppsyncPlugin {
       });
     this.writeText = this.helpers?.writeText || console.log;
 
+    this.configurationVariablesSources = {
+      appsync: {
+        resolve: this.resolveVariable,
+      },
+    };
+
     this.commands = {
       appsync: {
         commands: {
@@ -446,6 +456,39 @@ class ServerlessAppsyncPlugin {
     );
   }
 
+  public resolveVariable: VariableSourceResolver = ({ address }) => {
+    const naming = new Naming(this.serverless.configurationInput.appSync.name);
+
+    if (address === 'id') {
+      return {
+        value: {
+          'Fn::GetAtt': [naming.getApiLogicalId(), 'ApiId'],
+        },
+      };
+    } else if (address === 'arn') {
+      return {
+        value: {
+          'Fn::GetAtt': [naming.getApiLogicalId(), 'Arn'],
+        },
+      };
+    } else if (address === 'url') {
+      return {
+        value: {
+          'Fn::GetAtt': [naming.getApiLogicalId(), 'GraphQLUrl'],
+        },
+      };
+    } else if (address.startsWith('apiKey.')) {
+      const [, name] = address.split('.');
+      return {
+        value: {
+          'Fn::GetAtt': [naming.getApiKeyLogicalId(name), 'ApiKey'],
+        },
+      };
+    } else {
+      throw new this.serverless.classes.Error(`Unknown address '${address}'`);
+    }
+  };
+
   handleConfigValidationError(error: AppSyncValidationError) {
     const errors = error.validationErrors.map(
       (error) => `     at appSync${error.path}: ${error.message}`,
diff --git a/src/types/serverless.ts b/src/types/serverless.ts
index fd238b5..da59dd8 100644
--- a/src/types/serverless.ts
+++ b/src/types/serverless.ts
@@ -73,6 +73,20 @@ export type CommandsDefinition = Record<
   }
 >;
 
+export type VariablesSourcesDefinition = Record<
+  string,
+  {
+    resolve: VariableSourceResolver;
+  }
+>;
+
+export type VariableSourceResolver = (param: {
+  address: string;
+  params?: string[];
+  options: Record<string, unknown>;
+  resolveVariable: (address: string) => string;
+}) => void;
+
 export type CliOptions = Record<string, string | boolean | string[]>;
 
 /**
diff --git a/tsconfig.json b/tsconfig.json
index c967161..6d1bb73 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,5 +13,5 @@
     "noImplicitAny": false
   },
   "include": ["src/**/*.ts", "src/**/*.d.ts"],
-  "exclude": ["node_modules"]
+  "exclude": ["node_modules", "src/__tests__"]
 }


Test patch:
diff --git a/src/__tests__/given.ts b/src/__tests__/given.ts
index cc98c81..7c749ec 100644
--- a/src/__tests__/given.ts
+++ b/src/__tests__/given.ts
@@ -11,7 +11,7 @@ export const createServerless = () => {
   serverless.config.servicePath = '';
   serverless.serviceOutputs = new Map();
   serverless.servicePluginOutputs = new Map();
-  set(serverless, 'configurationInput.custom.appSync', []);
+  set(serverless, 'configurationInput.appSync', appSyncConfig());
 
   return serverless;
 };
diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts
new file mode 100644
index 0000000..cd04324
--- /dev/null
+++ b/src/__tests__/index.test.ts
@@ -0,0 +1,81 @@
+import * as given from './given';
+
+const plugin = given.plugin();
+
+describe('variable', () => {
+  it('should resolve the api id', () => {
+    expect(
+      plugin.resolveVariable({
+        address: 'id',
+        options: {},
+        resolveVariable: () => '',
+      }),
+    ).toMatchInlineSnapshot(`
+      Object {
+        "value": Object {
+          "Fn::GetAtt": Array [
+            "GraphQlApi",
+            "ApiId",
+          ],
+        },
+      }
+    `);
+  });
+
+  it('should resolve the api url', () => {
+    expect(
+      plugin.resolveVariable({
+        address: 'url',
+        options: {},
+        resolveVariable: () => '',
+      }),
+    ).toMatchInlineSnapshot(`
+      Object {
+        "value": Object {
+          "Fn::GetAtt": Array [
+            "GraphQlApi",
+            "GraphQLUrl",
+          ],
+        },
+      }
+    `);
+  });
+
+  it('should resolve the api arn', () => {
+    expect(
+      plugin.resolveVariable({
+        address: 'arn',
+        options: {},
+        resolveVariable: () => '',
+      }),
+    ).toMatchInlineSnapshot(`
+      Object {
+        "value": Object {
+          "Fn::GetAtt": Array [
+            "GraphQlApi",
+            "Arn",
+          ],
+        },
+      }
+    `);
+  });
+
+  it('should resolve an api key', () => {
+    expect(
+      plugin.resolveVariable({
+        address: 'apiKey.foo',
+        options: {},
+        resolveVariable: () => '',
+      }),
+    ).toMatchInlineSnapshot(`
+      Object {
+        "value": Object {
+          "Fn::GetAtt": Array [
+            "GraphQlApifoo",
+            "ApiKey",
+          ],
+        },
+      }
+    `);
+  });
+});