Repository: sid88in/serverless-appsync-plugin (ts)

Issue:
Javascript resolvers supported now by AWS as Unit resolvers but not by the plugin
Hey guys,

AWS now supports JS resolvers as UNIT resolvers however if i define them as `kind: UNIT` into the serverless config of your plugin  it throws an error on deploy asking for the Mapping templates(related to VTL resolvers).

If i define them using the `functions:` sintax for pipeline resolvers then it works fine but as pipeline resolvers.

When are you gonna add the support for JS unit resolvers? if it is still supported what's the sintax to write them ? 

Many thanks!

Pull request description:
feat: support js runtime for unit resolver
Added support javascript runtime for unit resolver.
https://aws.amazon.com/jp/blogs/mobile/aws-appsync-now-supports-javascript-for-all-resolvers-in-graphql-apis/


Closes #616 

Patch:
diff --git a/doc/resolvers.md b/doc/resolvers.md
index bc9d20a..2c56782 100644
--- a/doc/resolvers.md
+++ b/doc/resolvers.md
@@ -33,11 +33,15 @@ appSync:
 - `caching`: [See below](#Caching)
 - `sync`: [See SyncConfig](syncConfig.md)
 
-## JavaScript vs VTL
+## JavaScript, VTL, or Direct Lambda
 
-When `code` is specified, the JavaScript runtime is used. When `request` and/or `response` are specified, the VTL runtime is used.
+When `code` is specified, the JavaScript runtime is used.
 
-If neither are specified, by default, the resolver is a PIPELINE JavaScript resolver, and the following minimalistic resolver handler is used.
+When `request` and/or `response` are specified, the VTL runtime is used.
+
+For [direct lambda](https://docs.aws.amazon.com/appsync/latest/devguide/direct-lambda-reference.html), set `kind` to `UNIT` and don't specify `request`, `response` or `code`. This only works with Lambda function data sources.
+
+If nothing is specified, by default, the resolver is a PIPELINE JavaScript resolver, and the following minimalistic code is used for the `before` and `after` handlers.
 
 ```js
 export function request() {
@@ -49,7 +53,16 @@ export function response(ctx) {
 }
 ```
 
-To use [direct lambda](https://docs.aws.amazon.com/appsync/latest/devguide/direct-lambda-reference.html), set `kind` to `UNIT` and don't specify `request` and `response` (only works with Lambda function data sources).
+Example of a UNIT JavaScript resolver.
+
+```yaml
+appSync:
+  resolvers:
+    Query.user:
+      kind: UNIT
+      dataSource: myDataSource
+      code: getUser.js
+```
 
 ## PIPELINE resolvers
 
diff --git a/src/resources/Resolver.ts b/src/resources/Resolver.ts
index 249777d..1a4039c 100644
--- a/src/resources/Resolver.ts
+++ b/src/resources/Resolver.ts
@@ -31,13 +31,22 @@ export class Resolver {
       FieldName: this.config.field,
     };
 
-    const isJsResolver = !(
-      this.config.kind === 'UNIT' ||
-      'request' in this.config ||
-      'response' in this.config
-    );
-
-    if (!isJsResolver) {
+    const isVTLResolver = 'request' in this.config || 'response' in this.config;
+    const isJsResolver =
+      'code' in this.config || (!isVTLResolver && this.config.kind !== 'UNIT');
+
+    if (isJsResolver) {
+      if (this.config.code) {
+        Properties.Code = this.resolveJsCode(this.config.code);
+      } else {
+        // default for pipeline JS resolvers
+        Properties.Code = DEFAULT_JS_RESOLVERS;
+      }
+      Properties.Runtime = {
+        Name: 'APPSYNC_JS',
+        RuntimeVersion: '1.0.0',
+      };
+    } else if (isVTLResolver) {
       const requestMappingTemplates = this.resolveMappingTemplate('request');
       if (requestMappingTemplates) {
         Properties.RequestMappingTemplate = requestMappingTemplates;
@@ -85,18 +94,6 @@ export class Resolver {
         MaxBatchSize: this.config.maxBatchSize,
       };
     } else {
-      if (isJsResolver) {
-        if (this.config.code) {
-          Properties.Code = this.resolveJsCode(this.config.code);
-        } else if (!this.config.code) {
-          Properties.Code = DEFAULT_JS_RESOLVERS;
-        }
-        Properties.Runtime = {
-          Name: 'APPSYNC_JS',
-          RuntimeVersion: '1.0.0',
-        };
-      }
-
       Properties = {
         ...Properties,
         Kind: 'PIPELINE',
diff --git a/src/types/plugin.ts b/src/types/plugin.ts
index ea56c8b..f29fbed 100644
--- a/src/types/plugin.ts
+++ b/src/types/plugin.ts
@@ -151,6 +151,7 @@ export type BaseResolverConfig = {
   type: string;
   request?: string | false;
   response?: string | false;
+  code?: string;
   caching?:
     | {
         ttl?: number;
@@ -171,7 +172,6 @@ export type UnitResolverConfig = BaseResolverConfig & {
 
 export type PipelineResolverConfig = BaseResolverConfig & {
   kind?: 'PIPELINE';
-  code?: string;
   functions: string[];
 };
 


Test patch:
diff --git a/src/__tests__/resolvers.test.ts b/src/__tests__/resolvers.test.ts
index 28ea5fe..36ac663 100644
--- a/src/__tests__/resolvers.test.ts
+++ b/src/__tests__/resolvers.test.ts
@@ -76,6 +76,62 @@ describe('Resolvers', () => {
       `);
     });
 
+    it('should generate JS Resources with specific code', () => {
+      const api = new Api(
+        given.appSyncConfig({
+          dataSources: {
+            myTable: {
+              name: 'myTable',
+              type: 'AMAZON_DYNAMODB',
+              config: { tableName: 'data' },
+            },
+          },
+        }),
+        plugin,
+      );
+      expect(
+        api.compileResolver({
+          type: 'Query',
+          kind: 'UNIT',
+          field: 'user',
+          dataSource: 'myTable',
+          code: 'resolvers/getUserFunction.js',
+        }),
+      ).toMatchInlineSnapshot(`
+      Object {
+        "GraphQlResolverQueryuser": Object {
+          "DependsOn": Array [
+            "GraphQlSchema",
+          ],
+          "Properties": Object {
+            "ApiId": Object {
+              "Fn::GetAtt": Array [
+                "GraphQlApi",
+                "ApiId",
+              ],
+            },
+            "Code": "Content of resolvers/getUserFunction.js",
+            "DataSourceName": Object {
+              "Fn::GetAtt": Array [
+                "GraphQlDsmyTable",
+                "Name",
+              ],
+            },
+            "FieldName": "user",
+            "Kind": "UNIT",
+            "MaxBatchSize": undefined,
+            "Runtime": Object {
+              "Name": "APPSYNC_JS",
+              "RuntimeVersion": "1.0.0",
+            },
+            "TypeName": "Query",
+          },
+          "Type": "AWS::AppSync::Resolver",
+        },
+      }
+      `);
+    });
+
     it('should generate Resources with direct Lambda', () => {
       const api = new Api(
         given.appSyncConfig({