Skip to content

IIIF Image API 2.1 server in an AWS Serverless Application

License

Notifications You must be signed in to change notification settings

mnyrop/serverless-iiif

 
 

Repository files navigation

serverless-iiif

Build Status Maintainability Test Coverage

Description

A IIIF 2.1 Image API compliant server written as an AWS Serverless Application.

Components

Prerequisites

  • Some basic knowledge of AWS.
  • An Amazon Web Services account with permissions to create resources via the console and/or command line.
  • An Amazon S3 bucket to hold the source images to be served via IIIF. Note: The Lambda Function will be granted read access to this bucket.

Quick Start

serverless-iiif comes in two flavors: Standalone (Lambda-only) and Caching (CloudFront-enabled). The Standalone version is much simpler, but lacks the following features:

  • Custom Domain Name
    • Standalone URLs are in the lambda-url.AWS_REGION.on.aws domain (e.g., https://fu90293j0pj902j902c32j902.lambda-url.us-east-1.on.aws/iiif/2/)
    • Caching URLs without Custom Domains are in the cloudfront.net domain (e.g., https://d3kmjdzzy1l5t3.cloudfront.net/iiif/2/)
  • Responses larger than ~6MB
  • CloudFront function support (for pre/post-processing requests and responses)

Deploying via the AWS Serverless Application Repository

serverless-iiif is distributed and deployed via the AWS Serverless Application Repository. To deploy it using the AWS Console:

  1. Click one of the following links to deploy the desired application from the AWS Console:
  2. Make sure your currently selected region (in the console's top navigation bar) is the one you want to deploy to.
  3. Scroll down to the Application settings section.
  4. Configure the deploy template:
    • Give your stack a unique Application name
    • Enter the name of the SourceBucket the service will serve images from
    • Check the box acknowledging that the app will create a custom IAM roles and resource policies (and if deploying the Caching version, that it will also deploy a nested application)
    • Optional: Enter or change any other parameters that apply to your desired configuration.
  5. Click Deploy.
  6. When all the resources are properly created and configured, the new stack should be in the CREATE_COMPLETE stage. If there's an error, it will delete all the resources it created, roll back any changes it made, and eventually reach the ROLLBACK_COMPLETE stage.
  7. Click the CloudFormation stack link.
  8. Click the Outputs tab to see (and copy) the IIIF Endpoint URL.

Deploying via the Command Line

  1. Make sure you have the SAM CLI and AWS CLI installed.
  2. Make sure the AWS CLI is properly configured with credentials that have sufficient access to manage IAM, S3, Lambda, and (optionally) CloudFront resources.
  3. Clone this repository.
  4. Copy .env.example to .env. Update the various values within.
  5. Build the application:
    $ npm run build
  6. Deploy the application:
    $ npm run deploy

You'll be prompted for various configuration parameters, confirmations, and acknowledgments of specific issues (particularly the creation of IAM resources and the deployment of an open/unauthenticated Lambda Function URL). 7. Follow the prompts to complete the deployment process and get the resulting endpoint.

Deleting the application

The easiest way to delete the application is either from the Lambda Applications Console or by deleting its CloudFormation Stack. If you deployed from the command line, you can also use the npm run delete command.

Source Images

The S3 key of any given file, minus the extension, is its IIIF ID. For example, if you want to access the image manifest for the file at abcdef.tif, you would get https://.../iiif/2/abcdef/info.json. If your key contains slashes, they must be URL-encoded: e.g., ab/cd/ef/gh.tif would be at https://.../iiif/2/ab%2Fcd%2Fef%2Fgh/info.json. (This limitation could easily be fixed by encoding only the necessary slashes in the incoming URL before handing it off to the IIIF processor, but that's beyond the scope of the demo.)

iiif-processor can use any image format natively supported by libvips, including JPEG 2000 (.jp2), but best results will come from using tiled, multi-resolution TIFFs. The Lambda Function wrapper included in this application assumes a .tif extension unless you set ResolverTemplate in your .env file.

Creating tiled TIFFs

Using VIPS

vips tiffsave source_image.tif output_image.tif --tile --pyramid --compression jpeg --tile-width 256 --tile-height 256

Using ImageMagick

convert source_image.tif -define tiff:tile-geometry=256x256 -compress jpeg 'ptif:output_image.tif'

Testing

If tests are run locally they will start in "watch" mode. If a CI environment is detected they will only run once. From the project root run:

npm test

To generate a code coverage report run:

npm test --coverage

Custom Sharp Layer

This lambda uses the Sharp layer from https://github.com/samvera/lambda-layer-sharp-jp2/releases in order to get a version of Sharp with jp2 support. You can build your own local version using that code and then copy the file to serverless-iiif/sharp-lambda-layer.x86_64.zip. Then set LOCAL_SHARP=true and build/deploy to use your own version.

Advanced Usage

The SAM deploy template takes several optional parameters to enable the association of CloudFront Functions or Lambda@Edge Functions with the CloudFront distribution. These functions can perform authentication and authorization functions, change how the S3 file and/or image dimensions are resolved, or alter the response from the lambda or cache. These parameters are:

  • OriginRequestARN: ARN of the Lambda@Edge Function to use at the origin-request stage
  • OriginResponseARN: ARN of the Lambda@Edge Function to use at the origin-response stage
  • ViewerRequestARN: ARN of the CloudFront or Lambda@Edge Function to use at the viewer-request stage
  • ViewerRequestType: Type of viewer-request Function to use (CloudWatch Function or Lambda@Edge)
  • ViewerResponseARN: ARN of the CloudFront or Lambda@Edge Function to use at the viewer-response stage
  • ViewerResponseType: Type of viewer-response Function to use (CloudWatch Function or Lambda@Edge)

These functions, if used, must be created, configured, and published before the serverless application is deployed.

Examples

These examples use CloudFront Functions. Lambda@Edge functions are slightly more complicated in terms of the event structure but the basic idea is the same.

Simple Authorization

function handler(event) {
    if (notAuthorized) { // based on something in the event.request
       return {
         statusCode: 403,
         statusDescription: 'Unauthorized'
       };
    };
    return event.request;
}

Custom File Location / Image Dimensions

function handler(event) {
  var request = event.request;
  request.headers['x-preflight-location'] = {value: 's3://image-bucket/path/to/correct/image.tif'};
  request.headers['x-preflight-dimensions'] = {value: JSON.stringify({ width: 640, height: 480 })};
  return request;
}

Note: The SAM deploy template adds a preflight=true environment variable to the main IIIF Lambda if a preflight function is provided. The function will only look for the preflight headers if this environment variable is true. This prevents requests from including those headers directly if no preflight function is present. If you do use a preflight function, make sure it strips out any x-preflight-location and x-preflight-dimensions headers that it doesn't set itself.

Notes

Lambda Function URLs have a payload (request/response body) size limit of approximately 6MB in both directions. To overcome this limitation, the Lambda URL is configured behind an AWS CloudFront distribution with two origins - the API and a cache bucket. Responses larger than 6MB are saved to the cache bucket at the same relative path as the request, and the Lambda returns a 404 Not Found response to CloudFront. CloudFront then fails over to the second origin (the cache bucket), where it finds the actual response and returns it.

The cache bucket uses an S3 lifecycle rule to expire cached responses in 1 day.

License

serverless-iiif is available under the Apache 2.0 license.

Contributors

Contributing

If you're working on a PR for this project, create a feature branch off of main.

This repository follows the Samvera Community Code of Conduct and language recommendations. Please do not create a branch called master for this repository or as part of your pull request; the branch will either need to be removed or renamed before it can be considered for inclusion in the code base and history of this repository.

About

IIIF Image API 2.1 server in an AWS Serverless Application

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 95.8%
  • Shell 4.2%