GitHub - nicobistolfi/eagle-image-api: Free and open source Image Optimization & Transformation API built in Go using govips (libvips) and Serverless. Ready to be deployed on AWS Lambda and CloudFront.

5 min read Original article ↗

Author License Go Version Go Report Card Go Reference Build Status Postman

Free and open source Image Optimization & Transformation API built in Go using govips (libvips) and Serverless. Ready to be deployed on AWS Lambda and CloudFront.

How to deploy to AWS and Run

How to deploy to AWS and Run - Watch Video

Table of contents

Eagle CLI

The eagle CLI lets you deploy the Eagle Image API to your own AWS account with a single command.

Install via Homebrew

brew install nicobistolfi/carbon/eagle

Install via Go

go install github.com/nicobistolfi/eagle-image-api/cmd/eagle@latest

Usage

# Deploy to AWS (dev stage, us-west-1)
eagle deploy

# Deploy to production in a specific region
eagle deploy --stage prod --region us-east-1

# Deploy with custom parameters
eagle deploy --stage dev --quality 90 --webp true --avif true

# Use a local CloudFormation template
eagle deploy --template ./template.yml

# Show version
eagle --version

# Show help
eagle deploy --help

The deploy command will:

  1. Fetch the CloudFormation template from GitHub (or use a local --template)
  2. Create an ECR repository in your AWS account if needed
  3. Pull the public Docker Hub image and push it to your ECR
  4. Create or update the CloudFormation stack
  5. Print the API Gateway and CloudFront URLs on success

AWS credentials are read from the standard credential chain (environment variables, ~/.aws/credentials, IAM role).

Getting started

Prerequisites

  • Go 1.22+
  • libvips 8.10+ (brew install vips on macOS, apt install libvips-dev on Ubuntu)
  • Task (go install github.com/go-task/task/v3/cmd/task@latest or brew install go-task)
  • Docker (for deployment)
  • Serverless Framework (npm install -g serverless)

Setting up .env file

First copy and rename the .env.example file.

Then change the values to your needs. Use the following table to understand what each variable does.

Variable Accepted values Comments
ENVIRONMENT production / development
API_ENDPOINT /api/v1/image the path to access the api
PORT 3000 The port you want it to run locally.
QUALITY 90 Suggested between 70 and 90 depending on the use case
FIT outside Default resize fit mode
LOG_LEVEL error / warn / info / debug
ORIGIN_WHITELIST yourorigin.com,other.com Use * to allow all origins
REDIRECT_ON_ERROR false Will redirect to original image on error
WEBP true/false Enables webp format if accept header includes image/webp
AVIF true/false Enables avif format if accept header includes image/avif
AVIF_MAX_MP Number Maximum megapixels for avif format on output.

Run locally

# Build
task build

# Run tests
task test

# Run locally
task dev

# List all available tasks
task

You can try it by accessing the following url on your browser:

http://localhost:3000/dev/api/v1/image?url=https%3A%2F%2Feagle-image-test.s3.us-west-1.amazonaws.com%2Fpublic%2Feagle-2.jpg

The url query param is required and should be a valid url encoded string. In this case for testing purposes we are using an image hosted on S3. The original image URL is:

https://eagle-image-test.s3.us-west-1.amazonaws.com/public/eagle-2.jpg

Photo by Philipp Pilz on Unsplash

Photo by Philipp Pilz on Unsplash

Deploy to AWS

The API is deployed as a Docker container on AWS Lambda via Serverless Framework.

# Deploy to dev (via Serverless Framework)
sls deploy --stage dev

# Deploy to production (via Serverless Framework)
sls deploy --stage production

Run in Postman

To run and test the API you can use the following Postman collection

Run In Postman

Usage

The API uses query params to transform the images.

Query param Description Values
url URL that points to the original location of the image (URL-encoded) String (required)
width Width Number
height Height Number
fit When both a width and height are provided, the possible methods by which the image should fit these are: cover / contain / fill / inside / outside
position When using a fit of cover or contain, the default position is centre. Other options are: top, right top, right, right bottom, bottom, left bottom, left, left top
quality Quality Number (0-100)
lossless Use lossless compression mode Boolean
blur Gaussian blur Number (0-100)
sharpen Sharpen Number (1-100)
flip Flip vertically Boolean
flop Flip horizontally Boolean
rotate Rotate by angle Number (degrees)
webpEffort WebP compression effort Number (0-6)
alphaQuality Quality of alpha layer Number (0-100)
loop GIF number of animation iterations, use 0 for infinite Number
delay GIF delay between frames (in milliseconds) Number

Usage examples

You can use the following examples to understand how to use it. Remember to replace the API_ENDPOINT with the one you set on your .env file.

Resize

{{API_ENDPOINT}}/api/v1/image?width=400&height=400&url={{IMAGE_URL}}

Resized image

View original api response here

Resize and crop with fit cover

{{API_ENDPOINT}}/api/v1/image?width=400&height=400&fit=cover&url={{IMAGE_URL}}

Resized image

View original api response here

Resize and crop with fit contain

This will deform the image to fit the size

{{API_ENDPOINT}}/api/v1/image?width=400&height=400&fit=contain&url={{IMAGE_URL}}

Resized image

View original api response here

Resize and crop with position top

{{API_ENDPOINT}}/api/v1/image?width=400&height=400&fit=cover&position=top&url={{IMAGE_URL}}

Resized image

View original api response here

Resize and crop with position and quality

For the purpose of this test we set quality=10 just to test it, normally you should use quality between 70-90

{{API_ENDPOINT}}/api/v1/image?width=400&height=400&fit=cover&position=top&quality=10&url={{IMAGE_URL}}

Resized image

View original api response here

Lossless compression

{{API_ENDPOINT}}/api/v1/image?quality=80&lossless=true&url={{IMAGE_URL}}

Resized image

View original api response here