ぴこぴよの余白つき画像のサイズを変更しました

いつもぴこぴよをお使いいただきありがとうございます。(ぴこぴよ内に設置したアンケートで「つかってるよ~」とお声をいただき、制作の励みにしております。)

picopiyo.garakuta-toolbox.com

f:id:piyorinpa:20211020223702p:plain
余白付き画像

これまで、編集画面の「余白を付けずに画像を投稿」を設定しない場合、ドット絵の拡大率によらず、画像サイズを900 x 510px 固定としてツイートしていました。この画像サイズを 630 x 380px に変更しました。

これまでの画像サイズ 900 x 510px で投稿した場合、Twitterのサムネイル画像においてドット絵がきれいに表示されないことを確認しました。下図のように、投稿されたサムネイル画像を拡大してみると、入力画像とは異なる色味になっていることがわかります。

f:id:piyorinpa:20211020225411p:plain
サムネイル画像がくずれてしまう

サイズ 900 x 510px の画像をアップロードしたとき、Twitterのサムネイル画像は 630 x 380px で投稿されているようなので、アップロードする画像も 630 x 380px としたところ、これまでよりきれいに投稿できることを確認しました。

f:id:piyorinpa:20211020230031p:plain
投稿された画像

実際のツイートのようすはこちら

ということで、きれいにドット絵を投稿できるようになったぴこぴよを今後ともよろしくお願いします。投稿ページにアンケートを設置してるので、よければ使い心地や不具合報告、励ましの投稿をいただけると開発のモチベーション向上につながります。

ではでは。姉妹サービスの「みんなでつくるダンジョン」のほうもあわせてよろしくお願いします。

GitHub Issue Timeline APIでProjectの状態にとどまった時間を取得する

GitHubにはIssueのタイムラインを取得できるTimeline APIがあります。Issueのコメントだけではなく、たとえば「いつ、どのラベルを付与したか」や「いつ、どのProject Columnに移動したか」などを取得できます。(GitHubドキュメント に記載の通り、GitHub Project に関する情報を Timeline APIで取得する機能は開発者プレビュー段階とのことで、 リクエストヘッダに Accept: application/vnd.github.starfox-preview+json を付与することで取得できます)

たとえばこんなかんじのコマンドでリクエストできます。

curl \
  -H "Accept: application/vnd.github.mockingbird-preview+json" \
  -H "Accept: application/vnd.github.starfox-preview+json" \
  "https://api.github.com/repos/{owner}/{repo}/issues/{issue_id}/timeline"

こんなレスポンスが返ってきます。(一部を抜粋しています)

[
  {
    "id": 5272014742,
    "event": "converted_note_to_issue",
    "created_at": "2021-09-08T12:34:49Z",
    "project_card": {
      "id": 68365408,
      "url": "https://api.github.com/projects/columns/cards/68365408",
      "project_id": 13191782,
      "project_url": "https://api.github.com/projects/13191782",
      "column_name": "TODO"
    }
  },
  {
    "id": 5272041752,
    "event": "moved_columns_in_project",
    "created_at": "2021-09-08T12:39:42Z",
    "project_card": {
      "id": 68365408,
      "url": "https://api.github.com/projects/columns/cards/68365408",
      "project_id": 13191782,
      "project_url": "https://api.github.com/projects/13191782",
      "column_name": "Doing",
      "previous_column_name": "TODO"
    }
  },
   {
    "id": 915208714,
    "created_at": "2021-09-08T12:48:10Z",
    "updated_at": "2021-09-08T12:48:10Z",
    "author_association": "NONE",
    "body": "コメント",
    "performed_via_github_app": null,
    "event": "commented",
  },
  {
    "id": 5287257709,
    "event": "labeled",
    "created_at": "2021-09-11T06:22:04Z",
    "label": {
      "name": "label1",
      "color": "EAA6C8"
    }
  },
  {
    "id": 5287262270,
    "event": "closed",
    "created_at": "2021-09-11T06:29:45Z"
  }
 ]

event パラメータによって「なにが行われたか」が分かります。たとえばこんなかんじ。

event 何が行われたか
labeled ラベルが付与された
unlabeled ラベルが外された
added_to_project プロジェクトに追加された
converted_note_to_issue プロジェクトカードをIssueにした
moved_columns_in_project プロジェクトカードを移動した

また、各イベントのオブジェクトには created_at パラメータが存在するので、eventパラメータと組み合わせると、ラベルが付与されていた時間や、プロジェクトのある状態にとどまった時間を集計することができます。

これらを行うGitHub Actionsを書いてみました。

github.com

たとえば、私は自身のGitHub Projectで趣味開発のタスク管理をしていたりしますが、このActionsを導入することで、なににどれくらい時間がかかっているかを簡単に確認できるようになります。

こんなかんじに使います。Issueが閉じられたタイミングで、ラベルが付与された時間やプロジェクトにかかった時間をコメントします。

name: issue-closed

on:
  issues:
    types:
      - closed

jobs:
  closed:
    runs-on: ubuntu-latest
    steps:
      - name: Report
        id: report
        uses: piyoppi/actions-labeled-duration@abf85a23b076409eb646c7319d72c3a9e7167e27
        with:
          labels: label1,label2  # 集計対象のラベル(Optional)
          project_columns: TODO,Doing # 集計対象のプロジェクトカラム名(Optional)
          issue_comment: '⌛このIssueの作業にかかった時間は以下の通りです'  # Issueのコメント(Optional)

実行するとこんなかんじ になります。

ちまちまと使いながら手を入れていこうと思っています。ではでは。

みんなでつくるダンジョンに「マップチップ」モードを追加しました

みんなでつくるダンジョンにマップチップモードを追加しました。いわゆる「マップチップ」を並べてマップが作れるようになりました。

f:id:piyorinpa:20210802220558g:plain

こんなマップがつくれます。現状、「見下ろしビューモード 」 のみ対応しています(横スクロールマップも作れますが、衝突処理に難があります)。

dungeon.garakuta-toolbox.com

機能の概要などについては、以前に公開した以下のブログ記事を参照してください。作れるマップの雰囲気がわかると思います。 garakuta-toolbox.hatenablog.com

使い方については、以下のドキュメントを参照してください。

garakuta-toolbox.com

一応「試験公開」ということにしています。こんな機能があったらいいな~などあれば、おきがるに @piyorinpa まで教えてください。みなさんがこの機能を使ってくれると、機能追加などをしよう~という気持ちになれます。

不具合報告は@piyorinpa あるいは 不具合報告フォーム までお願いします。

ではでは

LitでつくったWebComponentをJestでテストする

Lit(+TypeScript)でつくったWebComponentをJestでテストしたくなったので、行ったことをまとめておきます。

前提

  • テストやコンポーネントはTypeScriptで記述
  • ts-jestが導入済み
  • Lit 2.0.0 / Jest 26系で動作確認

テストを書いてみる

以下のようなコンポーネントを定義したとします。

import { LitElement, html, css } from 'lit'
import { property, customElement } from 'lit/decorators.js'

@customElement('test-component') 
export class TestComponent extends LitElement {
  @property({type: String}) title = ''

  render() {
     return html`
     <div>
       <span>${title}</span>
      </div>
    `;
  }
}

まずは JestのDOM操作に関するドキュメント を参考にテストを書いてみます。雰囲気はこんなかんじ。

// 以下のように読み込むことで @customElement decoratorによってコンポーネントが定義される
import '~/src/TestComponent'
// 型情報がほしいので別途TestComponentを読み込む
import { TestComponent } from '~/src/TestComponent'


test('Content should include a title', async () => {
  document.body.innerHTML = `
    <test-component title="タイトル"></test-component>
  `
  const component = document.getElementsByTagName('test-component')[0] as TestComponent

  // コンテンツが描画されるまで待つ
  await component.updateComplete

  // たとえばtitle attribute が正しくコンテンツに反映されていることを確認する
  expect(component.shadowRoot?.innerHTML.match(/タイトル/g)?.length).toEqual(1)  
})

Lit ドキュメントの Lifecycleの項 をみると、コンテンツの更新が完了すると updateComplete PromiseがResolvedになるとあるので、コンテンツが更新されてからテスト項目を確認していきます(更新される前にテスト項目を確認すると、変更が反映されていない可能性があり、思うような実行結果が得られません)。

DOMの操作・取得の関数(たとえば Element.innerHTML など)がテストでも使えるので、これを用いて actual な状態を確認していきます。

もし、 @customElement decoratorを使わずにコンポーネントを定義している場合は、以下のようにテスト内で customElements.define() を呼ぶことで同様にCustomElementを定義できます。

import { TestComponent } from '~/src/TestComponent'

customElements.define('test-component', TestComponent)

// 以下同じ

テスト中の document.getElementsByTagName で取得した componentTestComponentインスタンス化したものなので、メソッドやプロパティにアクセスすることもできます。TestComponent内の何かをモックしたい~みたいなこともできます。

テストを実行できるようにする

テストを実行してみると、以下のようなエラーが出てしまいます。

 FAIL  tests/TestComponent.test.ts
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /path/to/test-project/node_modules/lit/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import"@lit/reactive-element";import"lit-html";export*from"lit-element/lit-element.js";
                                                                                             ^^^^^^

    SyntaxError: Cannot use import statement outside a module

    > 1 | import { LitElement, html, css } from 'lit'
        | ^

Lit ライブラリ内に import 文があるので、これをJestが解釈できずにエラーになっているようです。Jestはデフォルトでは node_modules 配下のファイルをトランスパイルしないので、 エラーメッセージにある通り transformIgnorePatterns に手を加え、Lit関連ライブラリがトランスパイルされるようにします。

トランスパイルの対象はエラーメッセージのとおりjsファイルなので、 babel-jest を使ってトランスパイルされるようにします。(必要に応じて @babel/preset-env をインストールします)

JestのGetting Started を参考に、babel.config.js を以下のように記述します。

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current',
        },
      }
    ]
  ]
}

続いて、jest.config.js を以下のように設定します。

module.exports = {
  preset: 'ts-jest/presets/js-with-babel',
  transformIgnorePatterns: [
    "/node_modules/(?!(@lit|lit|lit-element|lit-html)/)"
  ]
}

これでテストを実行できるようになりました。めでたしめでたし。

(おまけ)Canvas要素を含むコンポーネントのテスト実行

CustomElementにCanvasに関する処理が含まれていた場合は、テストの実行に失敗することがあります。JestのDOM周りには jsdom が用いられていますが、READMEをみると Cavnas Support の項があります。 これによると、 node-canvs をインストールすればよいとのことなので試してみると、インストールして特に設定を変えることなく実行することができました。


LitのTestingの項 によると、Web Test Runner を使うのがおすすめだよ!と書いてあるので、これもおいおいさわってみよう~となっていました。ではでは~

modern-web.dev

最近の開発の記録(20210802)

最近の開発のきろくをばをば。みんなでつくるダンジョン のマップエディタ機能がほぼほぼ固まってきたのでした。こんな感じのマップエディタができつつあります。 (ちなみにこのマップエディタは pico2map として公開しています。まだ安定版ではありませんが、そのうちいろいろちゃんとします)

※記事中のマップに含まれる素材画像は、墨cmさまから提供いただいたものと、ぴぽや様(https://pipoya.net)からお借りしたものを使っています。

f:id:piyorinpa:20210802204815p:plain
マップ編集のようす

これまでのマップエディタは、このようにパーツを配置して並べていくようにマップを作り上げる方式でした。

f:id:piyorinpa:20210802205719g:plain
いままでのマップエディタ

さらに、昨年には 見下ろしビュー のマップをつくれるようになったため、これまでのアクションゲーム形式の横スクロールマップのほか、RPGのようなマップも作れるようになりました(こんなマップがつくれます)。しかしながら、「パーツを配置して並べていく」形式のマップエディタだと、RPG向け素材画像などが活用しづらいなどの問題がありました。

ということで以下のように、マップチップを並べてマップをつくっていくタイプのマップエディタを開発しているのでした。マップチップをぺたぺたと貼り付けていくようにマップをつくれます。また、いわゆるオートタイルをサポートし、道や川などをつくるときに使われるマップチップを自動生成/配置するので、便利になっています。

f:id:piyorinpa:20210802220430g:plain
マップチップを配置していくタイプのマップエディタ

レイヤーも4層つかうことができます。4枚目のレイヤーが「キャラクターより前側」に表示されるようになっています。

f:id:piyorinpa:20210802222732g:plain
レイヤーの切り替え

もちろん今まで通りの「パーツを並べる」方式でのマップ編集もサポートしており、マップチップとパーツを共存することができます。マップチップ編集ボタンを押すと、マップチップを配置できるようになります。

f:id:piyorinpa:20210802224306g:plain
パーツ配置とマップチップの切り替え

マップチップは(いまのところ)アニメーションをサポートしていませんが、これまでの「パーツ」はアニメーションや「プラグインの適用」ができるので、このようにねこや人を右往左往させたりできます。

f:id:piyorinpa:20210802222019g:plain
うごくひととねこ

マップチップはあくまでも「画像を並べる」だけなので、動きのあるものを作るときは引き続き「パーツを配置」していく形になります。


こんなかんじのマップエディタができつつあります。まだ最低限というかんじの機能ですが、遊んでいて楽しい感じになってきました。

いまはひたすら私自身が遊んでバグを見つけて直して...という作業を行って動作を安定させる方向で開発作業をしています。渋いバグなどは取れつつあるので、あともうちょっと~というかんじです。ではでは~

Amazon S3+CloudFront環境へGitHub Actionsをつかってデプロイする

静的サイトの配信のために、Amazon S3にファイルを設置してCloudFrontで配信する方法はよく行われていると思いますが、私の管理するアプリケーションでもこのような構成のものがあります。

というわけで、もっとかんたんにデプロイできるようにしたいな~ということで、GitHub Actionsでデプロイできるようにしたので、備忘録としてまとめました。

成果物のWorkflow

こんなかんじのWorkflowを定義します。私のアプリケーションの場合は事前にnode環境のセットアップ(actions/setup-node@v1)をしたり、ビルド( npm run build )してからS3にファイルを設置していますが、このへんはそれぞれのケースに応じて調整します。 Workflowのトリガは、今回は workflow_dispatch として任意のタイミングで実行することとしましたが、このへんもそれぞれのケースに応じて調整するとよさそうです。

name: Deploy to s3
on: workflow_dispatch

jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      # 成果物を生成する
      - uses: actions/setup-node@v1
        with:
          node-version: '16.x'
      - name: Cache dependencies
        uses: actions/cache@v2
        with:
          path: |
            **/node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
      - run: npm install
      - run: npm run build

      # S3にアップロードしてInvalidationリクエストを投げる
      - 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: (region)
      - run: aws s3 sync ./build s3://example-bucket
      - run: aws cloudfront create-invalidation --distribution-id (distribution-id) --paths "/*"

やっていることは概ねこんな感じです。

  • aws-actions/configure-aws-credentials@v1 をつかって認証情報をセットアップする
    • これを使うとawsコマンドを認証が済んだ状態+Regionをセットした状態で使うことができます。
    • (region) を任意のRegionに設定します。
  • aws s3 sync コマンドでビルドした成果物(など)をS3 Bucketに送信する
    • example-bucket の部分は任意のBucket名に置き換えます。
    • S3への各種リクエストにはお金がかかります。頻繁にこのActionsを実行する場合はこのことも考慮される必要がありそうです。
  • aws cloudfront create-invalidation でファイルの無効化を行い、CDNのサーバのコンテンツを差し替える( --paths "/*" とすることですべてのファイルを無効化する)
    • (distribution-id) の部分は任意のDistribution IDに置き換えます。
    • Invalidationにはお金がかかります。 CloudFrontのドキュメント によると、1000件までの無効化パスまでは無料のようです。頻繁にこのActionsを実行する場合はこのことも考慮される必要がありそうです。

Workflowを動かすためのAWSアクセスキーの準備

各種awsコマンドが使えるように、アクセスキーを準備します。上記Actionsで用いるコマンド( aws s3 sync , aws cloudfront create-invalidation)には以下の権限が必要です。 (s3 sync に必要な権限は、 こちらの記事 を参照しました)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::(bucket-name)/*"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::(bucket-name)"
            ]
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": [
                "cloudfront:CreateInvalidation"
            ],
            "Resource": [
                "arn:aws:cloudfront::(aws-account-id):distribution/(distribution-id)"
            ]
        }
    ]
}
  • (bucket-name) はアップロード先のBucket名を設定します。
  • (aws-account-id) は、アカウントIDを設定します。
  • (distribution-id) は、CloudFrontのDistribution ID を設定します。

これらのアクセス権限を持つIAM Userを作成し、アクセスキーとシークレットアクセスキーを取得します。これらを AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY として、それぞれGitHubリポジトリのSecretsに保存します

これで、さきほど定義したWorkflowが動作するようになります。

そのほか参考にしたもの

aws.amazon.com


ビルドやアップロード周りを自動化することで、うっかりアップロードしちゃいけないファイルをアップロードするなどのミスが減るので、気軽にデプロイができるようになりますね。ではでは~

JSON Schemaでお手軽アンケートフォーム

こんにちは。お手軽に自分のサイトに埋め込むアンケート的なやつを作りたいけど、Google Formsなどでは若干要件を満たさないというお悩みがありました。

  • ログインしているときだけアンケートに答えられるようにしたい
  • 入力フォームに隠しパラメータを埋め込みたい(<input type="hidden"> みたいなものを入れたい)
  • データの後加工をしたいので任意の場所にアンケート結果を保存したい

これらを解決するあれこれを作っていました(作っています)。

github.com

だいたいこんな感じのアプリケーションです。

  • JSON Schema に基づきアンケートフォームが表示される
  • アンケートを送信すると、サーバ側でJSON Schemaの内容に基づきバリデーションを行う
  • 適切な場所にアンケート結果を保存する

f:id:piyorinpa:20210608224119p:plain
こんなイメージで構成されるアプリケーション

保存したアンケートを集計したり、分析したりすることはこのアプリケーションではしないものとします。

このリポジトリはmonorepo構成で、いくつかのアプリケーションで構成されています。

アンケートフォーム

JSON Schemaに基づき、アンケートフォームを生成して表示する、Reactベースのアプリケーションです。

アンケートフォームの生成には react-jsonschema-form を使っています。JSON Schemaを与えることで、 適したInput要素を表示してくれます。このライブラリをベースに、アンケートフォームとして使いやすい形のデザインに調整しました。

このアプリケーションを起動し、 /surveys/:schemaId にアクセスすると、指定したJSON Schemaを指定したアンケート定義JSON Schema配信サーバから取得してフォームを表示します。

f:id:piyorinpa:20210608232110p:plain
アンケートフォームのルーティング

たとえば、このアプリケーションをビルドする際の環境変数 REACT_APP_SCHEMA_BASE_URL="https://example.com"として、以下のようなJSON Schemaを https://example.com/test-survey に設置するとします。

{
  "title": "アンケート",
  "description": "サンプルアンケートです",
  "type": "object",
  "required": ["useful"],
  "properties": {
    "useful": {
      "type": "string",
      "title": "満足度",
      "description": "このウェブサイトににどれくらい満足していますか?",
      "enum": [
        "とても満足",
        "まあまあ満足",
        "あまり満足じゃない",
        "不満"
      ]
    },
    "comment": {
      "title": "ご意見やご感想",
      "description": "ご意見やご感想、機能追加や改善のご要望などご自由にお書きください",
      "type": "string",
      "maxLength": 1000
    }
  }
}

/surveys/test-survey にアクセスしたら GET https://example.com/test-surveyJSON Schemaを取得し、以下のようなアンケートフォームを表示します。

f:id:piyorinpa:20210607235615p:plain
表示されるアンケート

送信ボタンを押すと、環境変数 REACT_APP_BASE_URL に指定したアンケート受付APIにアンケートをPOSTします。

埋め込みアンケートフォームと署名付きパラメータ

f:id:piyorinpa:20210608224217p:plain
埋め込みアンケートフォーム

このアンケートフォームをiframeを使ってサイトに埋め込んだとき、サイト側で生成した署名付きパラメータを受け取ることができます。アンケートと一緒に任意のパラメータを埋め込みたいときなどに使います。

アンケートを埋め込みたいページに以下のようにiframeを設置します。(アンケートフォームが http://localhost:3000 、埋め込み先ウェブサイトが http://localhost:3001 で起動しているとします。)

<!-- アンケートフォームが localhost:3000 で起動しているとする -->
<!-- 埋め込んでいるウェブサイトは localhost:3001 で起動しているとする -->
<iframe id="survey-form" src="http://localhost:3000/surveys/test-survey"></iframe>

たとえば、先ほどのアンケート test-surveyJSON Schemaに以下のようなキー reportBoxOptions を追加します。signedParameters には署名付きパラメータの定義を、embedded には埋め込み先ページのOriginを記述します。

{
 "title": "アンケート",
  "description": "サンプルアンケートです",
  "type": "object",
  "properties": { ... }
  "reportBoxOptions": {
    "signedParameters": {
      "type": "object",
      "required": ["loggedIn"],
      "properties": {
        "loggedIn": {
          "type": "boolean"
        }
      },
      "embedded": {
        "parentOrigin": "http://localhost:3001"
      }
    }
  }
}

この signedParameters に記載された形式のJSONをJWTに変換してアンケートフォームに渡します。

アンケートを埋め込みたいページのサーバサイド側でJWTを生成します(secret秘密鍵

const jwt = require('jsonwebtoken');
const secret = 'test-secret';

// 今のところパラメータの暗号化を考慮していないので、秘密の情報は入れないこと
const signedParameters= jwt.sign({ params: { loggedIn: true } }, secret);

アンケートを埋め込んだページに以下のような処理を追加します。

<script type="text/javascript">
  const iframe = document.getElementById('survey-form');
  const formOrigin = 'http://localhost:3000';

  window.addEventListener('message', e => {
    // アンケートフォームから送られたメッセージでなければ受け取らない
    if (e.origin !== formOrigin) return;

    // アンケートフォームからSignedParameters受け取り準備完了のメッセージを受け取ったら
    // アンケートフォームへSignedParameters(をJWTエンコードした値)を送信する
    if (e.data.event === 'readyToReceiveSignedParameters') {
      // (signedParameters は埋め込み先のサーバ側で生成したJWT)
      iframe.contentWindow.postMessage(signedParameters, formOrigin);
    }
  })
</script>

アンケートフォーム側から signedParameters の受け取り準備が完了したタイミングでメッセージが送出されるので、確認の上アンケートフォームへ signedParameters の JWT を渡します。

アンケート送信時にこのJWTも一緒に送信され、アンケート受付APIでデコードされます。署名検証に成功したら、データストアに保存します。

JSON Schemaに signedParameters の設定を記述した場合は、署名付きパラメータがアンケート受付APIへのリクエストボディに含まれないと保存されないので、たとえばログインしていない人にはアンケートを 送信してほしくないなどの用途にもつかえます。

アンケート回答後の遷移先の指定

JSON SchemaにreportBoxOptions.callbackUrl パラメータを指定することで、アンケートを回答した後に任意のページに遷移させることができます。 完了画面を表示したり、アンケート回答後に何らかのアクションをしたいときに使います。

{
 "title": "アンケート",
  "description": "サンプルアンケートです",
  "type": "object",
  "properties": { ... }
  "reportBoxOptions": { 
    ... ,
   "callbackUrl": "https://example.com/callback"

  }
}

アンケート受付API

アンケートを受け取り、アンケート定義JSON Schemaサーバからアンケートに対応したJSON Schemaを取得したうえで、バリデーションをしてデータストアに保存します。 サーバ側のバリデーションには ajv をつかっています。

今回は、実装のひとつの例として、AWS環境(API Gateway と Lambda)にデプロイできるSAM TemplateとLambda Functionのサンプルを用意しました。 提出されたアンケートを検証(JSON Schemaを用いた入力値バリデーションと署名付きパラメータの署名検証)し、成功した場合はreportBoxMeta というメタデータを付与したうえで、指定したS3 Bucketにデータを保存します。

例えば先ほどの test-survey フォームを送信して検証が成功したとき、こんなデータが保存されます。

{
  "useful":"まあまあ満足",
  "comment":"ここをあれこれするともっといいと思います。",
  "loggedIn":true,
  "reportBoxMeta":{
    "metaDataVersion":1,
    "schemaId":"test-survey",
    "createdAtUtc":"2021-06-07T16:01:12.672Z"
  }
}

まとめ

JSON Schemaでアンケートが作れるそれっぽいアプリケーション群をお試しで実装してみました。好きな場所にアンケート結果を収集できるようになったので、集計やデータの加工がしやすくなったかなと思っています。 私の自作アプリケーションに組み込むなどしながら引き続き手を加えていきたいなと思っています。あと、せっかく作ったのでちゃんと使い方とかをまとめなければ...。

ではでは~。