概要
- 以前にQiitaの前日のいいね数を通知してくれるLINE Botを作りました
- この延長でいいね数の推移をグラフで表示するWebページを作ってみたというのが今回の内容です
- せっかくなので技術検証も兼ねてJamstackな構成で作ってみました
- 前述の記事の通りデータはDynamoDBにデータを蓄積しているのでHeadlessCMSなどは使わずにチャレンジしてみます
作ったもの
- 直近1週間のいいね数をグラフで表示するWebアプリをLIFFアプリとして表示しています
構成
- Jamstackな構成とするためにいろいろ使っているので少々複雑です
- 要素ごとに何をしているのか説明していきます
実装済みの機能
- Qiitaのいいね数を蓄積していく処理は前述の記事で紹介済みです
- LambdaでQiitaのAPIを叩き取得したデータをDynamoDBに保存しています
- Lambdaのバッチ実行で毎日0時に実行しています
Next.jsを使ったJamstackな仕組みの構築
- まずはビルドデプロイ自動化の仕組みは置いておいてアプリの部分からです
- Jamstackの最大の特徴であるビルド時にAPIアクセスしてデータ埋め込んだHTMLを生成するという部分です
- ビルド時にAPIアクセスできるライブラリはいくつかありますが今回はReactベースのNext.jsを使いました
- getStaticPropsとgetStaticPathsを使えれば簡単に実現できます
- こんな資料も過去に作ったのでご参考で
- この記事はJamstackにフォーカスしているので深く触れませんがLIFF SDKを入れてLIFFアプリ化しています
- LINE IDを取得できるのでログイン機能いらず!
GitHub ActionsでVercelに自動デプロイ
- 次はNext.jsで作ったアプリのデプロイ周りです
- 今回はホスティングサービスとしてVercelを使いました
- さらにGitHub Actionsで自動的にデプロイできる仕組みを作りました
- Vercel用のActionが公式であったのでそれを使っています
- GitHub Actions起動のトリガーはmasterへのプッシュとAPIアクセスを設定しています
.github/workflows/deploy.yml
name: deploy
on:
push:
branches:
- master
repository_dispatch:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 14
uses: actions/setup-node@v1
with:
node-version: 14
- uses: amondnet/vercel-action@v19
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
vercel-args: '--prod -f -b TZ=Asia/Tokyo -b REACT_APP_LIFF_ID=${{ secrets.REACT_APP_LIFF_ID }} -b REACT_APP_API_URL=${{ secrets.REACT_APP_API_URL }}'
vercel-org-id: ${{ secrets.ORG_ID}}
vercel-project-id: ${{ secrets.PROJECT_ID}}
DynamoDBの更新をトリガーにLambdaを起動してGitHub Actionsを叩く
- 最後にJamstack自動化の肝となるデータ更新をトリガーにビルドデプロイを走らせる仕組みです
- DynamoDB Streamsを使うことで特定のテーブルの更新をトリガーにLambdaを起動することができます
- そしてGitHub ActionsをAPIアクセスで起動できるようにしているためLambdaからそのAPIを叩いています
- ちょっとまわりくどいですがDynamoDBの更新をトリガーにGitHub Actionsを起動するために試行錯誤した結果です
- 他のサービスを使ったりすればもう少し違ったかな?
- 今回はLambdaやDynamoDB周りはServerlessFrameworkを使っています
- serverless.ymlはこんな感じです
serverless.yml(抜粋)
service:
name: line-qiita-bot
provider:
name: aws
runtime: nodejs12.x
region: ap-northeast-1
environment:
DYNAMODB_TABLE: ${self:service.name}-${self:provider.stage}
QIITA_HISTORY_TABLE: ${self:provider.environment.DYNAMODB_TABLE}-QiitaHistory
iamRoleStatements:
- Effect: Allow
Action:
- 'dynamodb:Query'
- 'dynamodb:Scan'
- 'dynamodb:GetItem'
- 'dynamodb:PutItem'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
- 'dynamodb:ListStreams'
- 'dynamodb:DescribeTable'
Resource: 'arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}*'
functions:
triggerGitHubActions:
handler: handler.triggerGitHubActions
events:
- stream:
type: dynamodb
batchSize: 1
startingPosition: LATEST
maximumRetryAttempts: 1
enabled: true
arn:
Fn::GetAtt:
- QiitaHistory
- StreamArn
resources:
Resources:
QiitaHistory:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:provider.environment.QIITA_HISTORY_TABLE}
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
- AttributeName: date
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: date
KeyType: RANGE
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
- Lambdaでの処理はAPIにアクセスしているだけです
- GitHub Actionsを起動するAPIはPOSTで
https://api.github.com/repos/アカウント名/リポジトリ名/dispatches
にアクセスする感じです - 詳細はドキュメントをご確認ください
- GitHub Actionsを起動するAPIはPOSTで
全体の流れ
- 少々複雑な構成でしたがこれで全部説明し終わりました
- 改めて全体の流れを振り返ります
- ①毎日0時にLambdaがバッチ実行されQiitaのAPIからいいね数を取得します
- ②取得したデータはDynamoDBに保存します
- ③DynamoDBにデータが保存されるとそれをトリガーにLambdaが起動します
- ④そのLambdaではGitHub Actionsを起動するAPIへのアクセスのみを行います
- ⑤APIアクセスにより起動されたGitHub ActionsではNext.jsで作られたアプリをビルドしVercelへのデプロイを行います
- ⑥〜⑨ビルド時にNext.jsのStatic Site Generationの機能によってAPIからいいね数のデータを取得してHTMLに埋め込みます
- ⑩生成された静的ファイルをVercelへデプロイします
- =>ユーザがページにアクセスすると最新データが反映されたグラフページが表示されます!
まとめ
- もともとDynamoDBにデータが蓄積されていたところからスタートしましたがなんとかJamstackな構成を実現できました!
- どこか一部分でも何かの参考になれば嬉しいです!