share facebook facebook2 twitter menu hatena pocket slack

2016.06.06 MON

AWS Lambda で S3 に置かれた Markdown を HTML に変換する

WRITTEN BY山口 与力

tl;dr

ES2015 で書くので前回参照。 S3 バケットに Markdown を置いたら Lambda Function が発火して、別のパスに HTML が出力されるようにしてみる。ソースはこちら

やりたいこと

4934602f-f239-9756-f660-c5f148e25f4c

ユーザーが Markdown をアップロードするのは /.src/ 以下、出力された HTML が出力されるのはバケット直下とします。

例: s3://orenobucket/.src/orenopage/index.md をアップロードすると s3://orenobucket/orenopage/index.html が出力される。

Lambda Function を書く

前回、 ES2015 で書いて簡単にデプロイできるようになったので、このリポジトリの内容から引き続き作業する前提で進めます。

まず、 S3 オブジェクトへの読み書きをしなくてはならないので、 AWS SDK を追加。 aws-sdk は Lambda の Node.js にはグローバルで導入されているので必須ではないですが…

$ npm install aws-sdk --save

さらに、 Lambda が使用する IAM Role で s3:GetObjects3:PutObject ができるようにしておくのを忘れずに。

もちろん Markdown を HTML に変換できなくてはならないので、今回は evilstreak/markdown-js を使用。

$ npm install markdown-js --save

せっかく Babel を使うのだから async/await を使ってみる。このために Babel の Stage 3 用 preset が必要。

$ npm install babel-preset-stage-3 --save-dev

Babel の設定ファイルにも stage-3 preset を追加。

.babelrc

{
  "presets": [
    "es2015",
    "stage-3"
  ]
}

できたのがこちら

functions/markdown2html/src/index.js

import lambda from 'apex.js'
import util   from 'util'
import AWS    from 'aws-sdk'

import {markdown} from 'markdown'

import 'babel-polyfill'

const s3 = new AWS.S3();

export default lambda(async (evt, ctx) => {
  let bucketName = evt.Records[0].s3.bucket.name;
  let srcKey     = evt.Records[0].s3.object.key;
  let destKey    = srcKey.replace(/^.src//, '').replace(/.md$/, '.html');

  let srcData = await s3.getObject({
    Bucket: bucketName,
    Key:    evt.Records[0].s3.object.key,
  }).promise();

  let markdownBody = (new Buffer(srcData.Body)).toString();

  let html = `
    
    
      
        Converted from s3://${bucketName}/${evt.Records[0].s3.object.key}
      
      
        ${markdown.toHTML(markdownBody)}
      
    
  `

  let destData = await s3.putObject({
    Bucket:      bucketName,
    Key:         destKey,
    Body:        html,
    ContentType: 'text/html',
  }).promise();

  return(destData);
});

async/await を使用することで、 S3 周りの非同期処理が極めてすっきり書けていることに注目されたい。

ソース全部はこちら。

追記: aws-sdk@2.3.0 で Promise がサポートされたので、自前で promisify する必要がなくなりました。最高。

S3 の Notification を設定する

S3 バケットの設定でイベントトリガーを追加する。

6dc1b263-68a4-d2a0-1415-6cdc409bc0c9

試してみる

test/index.md

# THE MOST EPIC MARKDOWN EVER

THE MOST EPIC PARAGRAPH!!

- THE MOST EPIC LIST ITEM 1
- THE MOST EPIC LIST ITEM 2
- THE MOST EPIC LIST ITEM 3

test/orenopage/index.html

**日本語** もいける?

[リンク](http://qiita.com/y13i)もしちゃうよ?

適当に Markdown ファイルを作って S3 にアップロードする。

$ aws s3 cp --recursive test/ s3://orenobucket/.src

ちゃんと動いているっぽい。

$ aws s3 ls s3://orenobucket/
                           PRE .src/
                           PRE orenopage/
2016-05-06 20:56:02        363 index.html

せっかくなので、静的ウェブサイトホスティングを有効化し、 Bucket Policy で Public Read な状態にしてブラウザーから見てみる。

fdb217e0-f8d1-4800-b394-5be50037afe4

00b52a6c-0317-77b5-e08e-3f5efb951a7d

はい。

参考

元記事はこちら

AWS Lambda で S3 に置かれた Markdown を HTML に変換する