いいねカウンタ @piyoppi/counter-tools を作りました

先日の記事 でブログにいいねできるようになった旨お知らせしましたが、このために @piyoppi/counter-tools を作りました。

せっかくつくったので、このアプリケーションについてご紹介します。

(このページは @piyoppi/counter-tools の実装の変更に伴い更新される可能性があります。)

@piyoppi/counter-tools とは?

Webページ(=URL)ごとに「いいね」を受け付けたり、現在の「いいね」の数を取得したりするアプリケーションです。

各ページに「いいね」ボタンを設置したり、カウント値を表示するカスタム要素を設置することができます。

@piyoppi/counter-tools の構成

system

このアプリケーションは以下の要素で構成されています。

各種サーバサイドのリソースにAWSが提供するサービスを用いています。

@piyoppi/counter-api は「カウント値の返却」「インクリメント」のエンドポイントを持っており、いずれもURLをリクエストパラメータとして受け付けます。 このURLは「現在表示中のウェブページのURL」が設定されることを期待しています。 このURLがStorage(S3)に配置されたURLホワイトリスト内に存在すれば、データベース内のカウンタをインクリメントします。

actions-upload-url-whitelist-to-s3 にサイトマップを入力することで、URLホワイトリストをGitHub ActionsのWorkflowで生成し、Storage(S3)にアップロードできます。

@piyoppi/counter-button はこれらのエンドポイントを利用してカウント値を表示したり、カウンタをインクリメントするUIを提供します。

アプリケーションの使い方

@piyoppi/counter-tools を予めクローンしておきます。

git clone git@github.com:piyoppi/counter-tools.git

@piyoppi/counter-api のデプロイ

まずは @piyoppi/counter-api をデプロイします。

このアプリケーションは Serverless Framework を用いて構成を管理しています。 serverlessコマンドをインストールします。

npm install -g serverless

また、お使いのAWSアカウントに紐づく各種リソースを作成するために、AWS CLIを使うなどして資格情報をセットアップしておきます

ここまでの準備が完了したら、@piyoppi/counter-tools のリポジトリ内の packages/counter に移動し、パラメータを適切な値に変更したうえで以下のコマンドを実行します。

cd packages/counter
serverless deploy \
  --param='sitemap=https://example.com/sitemap/sitemap-index.xml' \
  --param='bucket=counter-settings' \
  --param='urllist=urllist' \
  --param='origin=http://localhost:3000'

各パラメータは以下のように設定します。

パラメータ設定する値
sitemapサイトマップのURLhttps://example.com/sitemap/index.xml
bucketURLホワイトリストを設置するS3バケット名(デプロイとともに作成される)counter-settings
urllistURLホワイトリストのオブジェクト名urllist
origin設置対象のページのオリジンhttps://example.com

デプロイが完了したら、URLホワイトリストを更新します。デプロイされたLambda Functionのうち、「updateUrlList」を呼び出します。 このLambda Functionはデプロイ時にsitemapパラメータに設定したサイトマップにアクセスし、設定したS3バケットにURLホワイトリストのオブジェクト(オブジェクト名はデプロイ時に指定したurllistパラメータの値)を配置します。

(この作業は actions-upload-url-whitelist-to-s3 を使って自動化することができます。)

aws lambda invoke --function-name counter-dev-updateUrlList out --log-type Tail --query 'LogResult' --output text |  base64 -d

作業が完了したら、以下のようなコマンドでインクリメントできるようになります。urlパラメータに指定するURLは、URLホワイトリストに含まれている必要があります。

curl -X POST \
  -H'content-type: application/json' \
  -d'{"url": "https://example.com/weblog/"}' \
  https://xxxxxxx.execute-api.xxxxx.amazonaws.com/count

@piyoppi/counter-button の配置

elements

@piyoppi/counter-button は3つのコンポーネントを提供します。

  • <counter-display> : カウントの表示
  • <counter-increment-button> : カウントをインクリメントするボタン
  • <counter-container> : 上記2つのコンポーネントを管理するコンポーネント

import構文で読み込む場合は以下のようにロードします。

import '@piyoppi/counter-button'

スクリプトタグで読み込む場合は、対象のページに以下のように記述します。

<script src="https://cdn.jsdelivr.net/npm/@piyoppi/counter-button@0.1.4/dist/counter-button.umd.js"></script>

以下のようにマークアップを記述します。 <counter-container> の apiurl属性には、@piyoppi/counter-api のデプロイによって払い出されたAPIのベースURLを設定します。 <counter-display><counter-container> にはほとんどスタイルが適用されていないので、自分でCSSを用意するなどして見た目を整える必要があります

<counter-container
  apiurl="https://xxxxxxx.execute-api.xxxxx.amazonaws.com"
  >
  <counter-increment-button>
    <span>
      🌟
      <counter-display>
        <span slot="loading">...</span>
        <span slot="error">error</span>
      </counter-display>
    </span>
  </counter-increment-button>
</counter-container>

actions-upload-url-whitelist-to-s3 によるサイトマップ更新の自動化

@piyoppi/counter-api でデプロイされるLambda function「updateUrlList」を実行することで、サイトマップからURLホワイトリストを生成できますが、GitHub Actionsが使える環境の場合はこの作業を簡単に自動化できます。

たとえば、以下のようなディレクトリ構成の中にサイトマップが存在するとします。

.
|-- public
|   `-- sitemap
|       |-- sitemap-index.xml
|       |-- sitemap-0.xml
|       `-- sitemap-1.xml

これらのサイトマップは以下のURLで公開されているとします。

https://garakuta-toolbox.com/sitemap/sitemap-index.xml
https://garakuta-toolbox.com/sitemap/sitemap-0.xml
https://garakuta-toolbox.com/sitemap/sitemap-1.xml

この場合、以下のようにGitHub Actions Workflowを記述することで、リポジトリ内のサイトマップをURLホワイトリストの形式に整形し、指定のS3 Bucketにアップロードできます。

name: Update counter urls v2

on:
  workflow_dispatch:
  push:
    branches:
      - master

jobs:
  update-counter-urls:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      # 予めアクセスキーを用いて資格情報をセットしておく必要がある
      - uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      
      - uses: piyoppi/actions-counter-tools-upload-url-whitelist-to-s3@main
        with:
          sitemap_filename: ${{ github.workspace }}/public/sitemap/sitemap-index.xml   # サイトマップのエントリポイントのFull Path
          sitemap_baseurl: https://garakuta-toolbox.com/sitemap/                       # サイトマップが存在するURL
          sitemap_basepath: ${{ github.workspace }}/public/sitemap/                    # サイトマップの存在するパス
          s3_bucket_name: ${{ secrets.S3_BUCKET_NAME }}                                # アップロード先のS3 Bucket(@piyoppi/counter-apiのデプロイ時に指定したS3 Bucket Nameを設定)
          output_urllist_filename: 'urllist'                                           # @piyoppi/counter-api をデプロイする際の urllist パラメータとして設定したURLホワイトリストオブジェクトの名前

まとめ

ウェブページにかんたんにいいねボタンを設置できるツールを作りました。もしかすると、今後は以下の機能を実装したいなと思っています。

  • 特定のクエリパラメータを許可することで、1ページに複数の投票ボタンを設置できるようにする
  • 署名付きリクエストをサポートし、ログインユーザーのみが投票できるようにする

カウンタに特化したアプリケーションにしていこうと思っています。ではでは~。