Lambda Function can't resolve layer code (nodejs)

Viewed 269

Introduction

I am using layers to avoid duplicate code. Currently I have one lambda function and one layer. But the function has problems using the layer.

I am using the AWS SAM to deploy it.

Project

The project looks like this:

backend/
├── lambdas/
│   └── onSignup/
│       ├── app.ts
│       └── package.json
├── layers/
│   └── SQLLayer/
│       └── nodejs/
│           ├── package.json
│           └── index.ts
└── template.yaml

template.yaml:

Resources:

  SQLLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
        LayerName: sql-dependencies
        Description: sql dependencies
        ContentUri: layers/SQLLayer/
        CompatibleRuntimes:
          - nodejs14.x
        LicenseInfo: 'MIT'
        RetentionPolicy: Retain
    Metadata: # Manage esbuild properties
      BuildMethod: nodejs14.x

  onSignup:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: lambdas/onSignup/
      Handler: app.lambdaHandler
      Runtime: nodejs14.x
      Timeout: 10
      Architectures:
        - x86_64
      Layers:
        - !Ref SQLLayer
    Metadata: # Manage esbuild properties
      BuildMethod: esbuild
      BuildProperties:
        Minify: false # set True on release
        Target: "es2020"
        Sourcemap: true
        EntryPoints: 
        - app.ts

Problem

I am now trying to import this layer into the app.ts from the lambda function like this. But it cant find the module.

var executeSqlStatement = require("/opt/SQLLayer/")

I have also tried countless other file paths but it doesn't work. Almost every resource I tried to use used another file path but none worked for me. But when I deploy them they are uploaded correctly. I am just not sure how they are put together on runtime.

Other mentions

I am not sure if this is a problem but when building I get this output:

Building layer 'SQLLayer'
package.json file not found. Continuing the build without dependencies. <=== COULD THIS BE A PROBLEM?
Running NodejsNpmBuilder:CopySource
Building codeuri: C:\coding\apps\iota\backend\lambdas\onSignup runtime: nodejs14.x metadata: {'BuildMethod': 'esbuild', 'BuildProperties': {'Minify': False, 'Target': 'es2020', 'Sourcemap': True, 'EntryPoints': ['app.ts']}} architecture: x86_64 functions: ['onSignup']
Running NodejsNpmEsbuildBuilder:CopySource
Running NodejsNpmEsbuildBuilder:NpmInstall
Running NodejsNpmEsbuildBuilder:EsbuildBundle

Build Succeeded

It says package.json was not found but the build continues and also succeeds. The layer can also be found in the build folder so I don't think this is a problem.

The other weird thing is that in the build folder for the layer there are two nodejs folders nested inside each other. But that could be normal but I just wanted to mention it for completion.

I hope you have enough information to help me.

Thanks!

2 Answers

It's because, in fact, that path doesn't really exist. You can do the following. Do the normal import:

var executeSqlStatement = require("/opt/SQLLayer/")

and in tsconfig.json change the settings to the following:

{
  baseUrl: "./",
  paths: {
    "/opt/SQLLayer/": "your path local"
  }
}

You did not specify which version of SAM CLI you were using. The information I am providing below is based on SAM CLI version 1.55.0.

So your layer code doesn't really follow your local hierarchy or include the name of the layer itself. The warning you get of the missing package.json is a warning that tells you the code is not been placed where you expect.

You need to remove the nodejs folder so your code looks like this

├── layers/
│   └── SQLLayer/       
│      ├── package.json
│      └── index.ts

This will create a layer with the current hierarchy

├── nodejs/
│   ├── package.json
│   └── index.ts

In your actual Lamabda function this will look like this

├── /opt/
│   └── nodejs/       
│      ├── package.json
│      └── index.ts

This means that you can import this module like this in your lambda function require('/opt/nodejs')

I hope you find this information useful to understand how you can structure the code of your lambda layers source code folder when using SAM CLI.

Related