javascript – ImageMagick lambda layer aws SAM

I have the following template.yaml from a SAM application

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  image-resizing-lambda-js

  Sample SAM Template for image-resizing-lambda-js

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3
    MemorySize: 1536

Resources:
  HelloWorldFunction:
    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: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs10.x
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: post
  imagemagicklambdalayer:
  Type: AWS::Serverless::Application
  Properties:
    Location:
      ApplicationId: arn:aws:serverlessrepo:us-east-1:145266761615:applications/image-magick-lambda-layer
      SemanticVersion: 1.0.0

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

With the following code.

Now I have read that I need to do the following to use ImageMagick with node on aws lambda is the following

Install the custom layer https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:145266761615:applications~image-magick-lambda-layer Link any lambda function using ImageMagick with that custom layer

It is the link any lambda function using ImageMagick with the custom layer I am confused. Do I need to do something different in my app.js code that points the imagemagick call in my code to the layer somehow. I am not entirely sure what a layer is. But my understanding is it is needed for ImageMagick to work.

Any help would be greatly appreciated

const axios = require("axios");
// const url="http://checkip.amazonaws.com/";
//const sharp = require("sharp");
const gm = require("gm");

const imageMagick = gm.subClass({ imageMagick: true });

let response;

/**
 *
 * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
 * @param {Object} event - API Gateway Lambda Proxy Input Format
 *
 * Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
 * @param {Object} context
 *
 * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
 * @returns {Object} object - API Gateway Lambda Proxy Output Format
 *
 */
exports.lambdaHandler = async (event, context) => {
  try {
    // const ret = await axios(url);
    const parsedBody = JSON.parse(event.body);
    response = {
      statusCode: 200,
      body: JSON.stringify({
        message: parsedBody.imagePath,
        // location: ret.data.trim()
      }),
    };

    const WEB_WIDTH_MAX = 420;
    const WEB_Q_MAX = 85;

    const url = "https://miro.medium.com/max/512/1*V395S0MUwmZo8dX2aezpMg.png";

    const data = imageMagick(url)
      .resize(WEB_WIDTH_MAX)
      .quality(WEB_Q_MAX)
      // .gravity('Center')
      .strip()
      // .crop(WEB_WIDTH_MAX, WEB_HEIGHT_MAX)
      .toBuffer("png", (err, buffer) => {
        if (err) {
          console.log("An error occurred while saving IM to buffer: ", err);
          return false; /* stop the remaining sequence and prevent sending an empty or invalid buffer to AWS */
        } else {
          console.log("buffer", buffer);
        }
      });

    // gmToBuffer(data).then(console.log);
  } catch (err) {
    console.log(err);
    return err;
  }

  return response;
};

Currently I get the following error when running sam build

Plugin 'ServerlessAppPlugin' raised an exception: 'NoneType' object has no attribute 'get'

Before adding the imagemagicklamdalayer section I was able to run sam build and have imagemagick run with the following error under sam local start-api after hitting the endpoint

An error occurred while saving IM to buffer:  Error: Stream yields empty buffer

I have got it to build with the following as the layer in the template.yaml

Layers:
        - "arn:aws:serverlessrepo:us-east-1:145266761615:applications/image-magick-lambda-layer"

Now I get an error on running the function like the following

File "/usr/local/Cellar/aws-sam-cli/1.46.0/libexec/lib/python3.8/site-packages/botocore/regions.py", line 230, in _endpoint_for_partition
    raise NoRegionError()
botocore.exceptions.NoRegionError: You must specify a region.

Not sure where I am to specifiy this region

UPDATE:

Ok two things one I set the region in my aws config file and I set the arn to the publish layer. I have gotten the following with something that hasn’t built yet in about 5 minutes so we shall see if it ever does.

It tries to build the layer when the function is invoked

Invoking app.lambdaHandler (nodejs12.x)
arn:aws:lambda:us-east-1:396621406187:layer:image-magick:1 is already cached. Skipping download
Image was not found.
Building image...................................................................

Leave a Comment