serverlessフレームワークでmail用APIを用意する
2022/06/09
serverlessはサーバーレスなアーキテクチャをかんたんに作成できるオープンソースのフレームワークです。 AWS Lambdaだけでなく、Azure Functions、Google CloudFunctionsなどに対応しています。
Set Up
今回はlabmdaを使用する前提ですすめます。
serverlessフレームワークはnpm
でインストール可能です。
$ npm install -g serverless
以下のコマンドでawsのlabmdaでnodeを動かすtemplateが作成されます。
$ serverless create --template aws-nodejs
このテンプレートでは以下のファイルが生成されます。
handler.js (Clickで詳細)
'use strict';
module.exports.hello = async event => {
return {
statusCode: 200,
body: JSON.stringify(
{
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
},
null,
2
),
};
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
serverless.yml (Clickで詳細)
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
# docs.serverless.com
#
# Happy Coding!
service: example
# app and org for use with dashboard.serverless.com
#app: your-app-name
#org: your-org-name
# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
frameworkVersion: '2'
provider:
name: aws
runtime: nodejs12.x
# you can overwrite defaults here
# stage: dev
# region: us-east-1
# you can add statements to the Lambda function's IAM Role here
# iamRoleStatements:
# - Effect: "Allow"
# Action:
# - "s3:ListBucket"
# Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] }
# - Effect: "Allow"
# Action:
# - "s3:PutObject"
# Resource:
# Fn::Join:
# - ""
# - - "arn:aws:s3:::"
# - "Ref" : "ServerlessDeploymentBucket"
# - "/*"
# you can define service wide environment variables here
# environment:
# variable1: value1
# you can add packaging information here
#package:
# include:
# - include-me.js
# - include-me-dir/**
# exclude:
# - exclude-me.js
# - exclude-me-dir/**
functions:
hello:
handler: handler.hello
# The following are a few example events you can configure
# NOTE: Please make sure to change your handler code to work with those events
# Check the event documentation for details
# events:
# - http:
# path: users/create
# method: get
# - websocket: $connect
# - s3: ${env:BUCKET}
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"
# - cloudwatchEvent:
# event:
# source:
# - "aws.ec2"
# detail-type:
# - "EC2 Instance State-change Notification"
# detail:
# state:
# - pending
# - cloudwatchLog: '/aws/lambda/hello'
# - cognitoUserPool:
# pool: MyUserPool
# trigger: PreSignUp
# - alb:
# listenerArn: arn:aws:elasticloadbalancing:us-east-1:XXXXXX:listener/app/my-load-balancer/50dc6c495c0c9188/
# priority: 1
# conditions:
# host: example.com
# path: /hello
# Define function environment variables here
# environment:
# variable2: value2
# you can add CloudFormation resource templates here
#resources:
# Resources:
# NewResource:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: my-new-bucket
# Outputs:
# NewOutput:
# Description: "Description for the output"
# Value: "Some output value"
テンプレートを作成できたらローカルですぐに動作確認ができます。
$ sls invoke local -f hello
# { message: 'Go Serverless v1.0! Your function executed successfully!', event };
local
を外すとdeploy先のlabmdaを叩きます。
Mailのhandlerを用意
handler.jsのようなMail用のhandlerを用意します。
const dayjs = require('dayjs');
dayjs.extend(require('dayjs/plugin/timezone'));
dayjs.extend(require('dayjs/plugin/utc'));
dayjs.tz.setDefault('Asia/Tokyo');
const nodemailer = require('nodemailer');
const { MAIL_HOST, MAIL_PORT, MAIL_USER, MAIL_PASS, MAIL_DEST } = process.env;
const transport = nodemailer.createTransport({
host: MAIL_HOST,
port: MAIL_PORT,
secure: true,
auth: {
user: MAIL_USER,
pass: MAIL_PASS,
},
});
module.exports.sendEmail = async (event) => {
const body = JSON.parse(event.body);
const now = dayjs.tz().format('YYYY/MM/DD HH:mm');
const text = `HPよりお問い合わせを受信しました。
+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-+:-+:-+:-+:-+
受付日時:${now}
■お問い合わせ情報
お問い合わせ内容:
${body.content}
■お客様情報
会社名 : ${body.company}
お名前 : ${body.name}
メールアドレス: ${body.mail}
お電話番号 : ${body.phone}
+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-:+:-+:-+:-+:-+:-+
`;
let info = await transport.sendMail({
from: `"お問い合わせフォーム" <${MAIL_USER}>`,
to: MAIL_DEST,
subject: 'お問い合わせ',
text,
});
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify(
{
message: 'send e-mail',
},
),
};
};
serverless.yml
のfunctionsに上のemailHandlerを追記します。
functions:
sendEmail:
handler:
emailHandler.sendEmail
# APIとして使用したいので、以下も記入
events:
- http:
path: email
method: post
hello:
handler: handler.hello
events: -http
を追記することでCloud FrontとAPI Gatewayをよしなに設定してくれます。
Lambdaへのdeploy
事前にIAMでcredentialsの設定(基本的にはaccess keyとsecret keyを登録するだけ)を行ったあと https://dev.classmethod.jp/articles/easy-deploy-of-lambda-with-serverless-framework/
以下のコマンドを実行するだけでdeployできます。
$ sls deploy
内部的には、CloudFormationのスタックを作成し、それに基づいてIAMやLambda等の設定を行っているっぽいです。 (Cloud Front、Cloud Watch、その他のサービスとの連携を自動でやってくれるので便利)
デプロイが完了すると以下のようなログが出ます。
Service Information
service: utility-mail-api
stage: prod
region: ap-northeast-1
stack: utility-mail-api-prod
resources: 14
api keys:
None
endpoints:
POST - https://example.execute-api.us-east-1.amazonaws.com/prod/email
functions:
sendEmail: utility-mail-api-prod-sendEmail
hello: utility-mail-api-prod-hello
layers:
None
ちなみにdeployを取り消したいときは以下のコマンドでOKです。
$ sls remove
CloudFormationを使っている関係上、aws consoleからマニュアルでdeployを削除したりするとめんどくさいことになる可能性があるので基本的にはコマンドからの削除を推奨します 😅
おわり
以下の要な場合にはserverlessはオススメ
- 複雑なAPIは必要ない
- サーバの管理をしたくない
- お金をかけたくない