4

We have a very simple use case--we want to share code with all of our lambdas and we don't want to use webpack.

We can't put relative paths in our package.json files in the lambda folders because when you do sam build twice, it DELETES the shared code and I have no idea why.

Answer requirements:

  • Be able to debug locally
  • Be able to run unit tests on business logic (without having to be ran in an AWS sandbox)
  • Be able to run tests in sam local start-api
  • Be able to debug the code in the container via sam local invoke
  • sam build works
  • sam deploy works
  • Runs in AWS Lambda in the cloud
Brandon
  • 695
  • 10
  • 29

1 Answers1

10

TL;DR

  • Put your shared code in a layer
  • When referencing shared code in the lambda layer, use a ternary operator when you require(). Check an environment variable that is only set when running in the AWS environment. In this case, we added a short AWS variable in the SAM template, but you can find environment variables that AWS automatically defines, but they will not be as short. This enables you to debug locally outside of the AWS stack, allowing very fast unit tests that test business logic.
let math = require(process.env.AWS ? '/opt/nodejs/common' : '../../layers/layer1/nodejs/common');
let tuc = require(process.env.AWS ? 'temp-units-conv' : '../../layers/layer1/nodejs/node_modules/temp-units-conv');
  • You shouldn't need to use the ternary operator like that unless within the lambda folder code

Here's a working example that we thought we'd post so that others will have a much easier time of it than we did. It is our opinion that AWS should make this much easier.

https://github.com/blmille1/aws-sam-layers-template.git


Gotchas

The following gotcha has been avoided in this solution. I am mentioning it because it looked like a straight-forward solution and it took a lot of time before I finally abandoned it.

It is very tempting to add a folder reference in the lambda function's package.json.

//...
"dependencies": {
    "common":"file:../../layers/layer1/nodejs/common"
},
//...

If you do that, it will work the first sam build. However, the second time you run sam build, your shared code folder and all subdirectories will be DELETED. This is because when sam builds, it creates an .aws-sam folder. If that folder exists, it performs an npm cleanup, and I think that is what provokes the deleting of the shared code.

Brandon
  • 695
  • 10
  • 29
  • 2
    This answer would be more useful if it explained the solution, with relevant quotes and code examples as needed, in the answer itself, as well as linking to the git template. This helps people find the answer, tell if the git repo has what they need, and lets the answer continue to be useful if the repo gets taken down or the link stops working :) – MyStackRunnethOver Mar 07 '20 at 00:05
  • 1
    @MyStackRunnethOver Thank you for the suggestion. If there is anything more that you think I should add, please let me know. – Brandon Mar 09 '20 at 16:04
  • 2
    Thanks for updating! Looks great :) – MyStackRunnethOver Mar 09 '20 at 18:14
  • 1
    @Brandon Thanks for your answer. I can now run tests for my lambdas. But, debugging the code in the container using sam local invoke is still not finding my layer using the relative path. If I manually set the env for AWS on my local, it works only after I build the function(which i have to repeatedly do after changing anything in the code). The /opt path or the relative path doesn't work when I don't build the changes everytime. Can you please help me out. Thanks – Swopnil Dangol Aug 24 '20 at 11:17
  • @SwopnilDangol I haven't found the environment to be awesome to develop in because, as you say, you have to do a lot of work for each invocation. I'm afraid that I don't have much to offer you in terms of "this is how you have an awesome development experience." Did you check out the link? I give some tips in there, but it's still not an awesome development experience. – Brandon Aug 26 '20 at 19:46
  • @Brandon Yeah, thanks anyways :) I checked the link and got the idea of using the layers. To make it a bit easier, I'm now just making the changes on the generated .aws-sam folder so that I don't have to build everytime but again copy the changes back to the source. Still not a perfect experience but beats having to build after each changes. – Swopnil Dangol Aug 27 '20 at 04:25
  • In order to import 'temp-units-conv' in lambda, it should be 'otp/node_modules/temp-units-conv'. You could confirm by download that layer on the lambda layer. – Long Nguyen Apr 09 '21 at 11:25
  • At least with jetbrains IDEs you can mark the local layer folder as source and then use only the layer's name as the import path but yea that's still pretty bad. I can't believe we have to do this, with python layers you can import it by its name and it work locally and on AWS like you'd expect. – Jasmin Parent Apr 29 '21 at 23:16