課題
microCMS+Nuxt.js+S3+CloudFrontの構成ででJamstackなWebサイトを構築している中で、microCMSから投稿した画像などのメディアファイルについてもS3でファイルを保管して、CloudFrontでCDN配信できるようにすることでより高速な表示ができるWebサイトを構築したい
考えた方法
microCMSのメディア投稿にはwebhookの機能がついており、メディアを追加/変更/削除した時にその内容をAPI経由で受け取ることができる。
そこで、webhookで受け取った情報を元にS3にファイルを保存するAPIをAPIGateway+Lambdaで作ることにした。
手順・実装内容
まずはLambda関数を作成した。
import boto3
from urllib.request import urlopen
# microCMSでメディアが追加/更新/削除されたらS3にも反映する
def lambda_handler(event, context):
# バケット名,オブジェクト名
s3 = boto3.resource('s3')
bucket = s3.Bucket('YOUR-BUCKET-NAME')
if event['type'] == 'new':
# S3に画像をアップロード
url = event['new']['url']
s3_path = url.replace('https://images.microcms-assets.io/', '')
bucket.upload_fileobj(urlopen(url), s3_path)
elif event['type'] == 'edit':
# 古いファイルを削除
old_url = event['old']['url']
old_s3_path = old_url.replace('https://images.microcms-assets.io/', '')
bucket.Object(old_s3_path).delete()
# 新しいファイルをアップロード
new_url = event['new']['url']
new_s3_path = new_url.replace('https://images.microcms-assets.io/', '')
bucket.upload_fileobj(urlopen(new_url), new_s3_path)
elif event['type'] == 'delete':
# S3から画像を削除
url = event['old']['url']
s3_path = url.replace('https://images.microcms-assets.io/', '')
bucket.Object(s3_path).delete()
# JSONを返す
return {
"statusCode": 200,
}
APIから通知された内容に応じてそれぞれ保存、差し替え、削除をするだけ。
「https://images.microcms-assets.io/」 より下の部分にはID的なものが2種類入った後にファイル名がくる形式で、これをS3上でもそのまま使うことで同名のファイルでも保存できるようにするとともに、microCMSとの紐付けを別途持たなくてもいいようにした。
次にこのLambda関数を使うAPIGatewayを作成する。
webhookはPOSTで送信されるのでAPIもPOSTにしておくこと。
(作業手順に特殊な部分ないので割愛)
あとはmicroCMSのメディア管理 > メディア設定 > webhookに作成したAPIのURLを記載すればメディアが追加/変更/削除されるたびにAPIが起動され、S3と同期される。