Amazon Amplify Gen 2 の React + Vite テンプレートで Amazon QuickSight Embedding SDK を使ったダッシュボード埋め込みを実装する

Amazon Amplify Gen 2 の React + Vite テンプレートで Amazon QuickSight Embedding SDK を使ったダッシュボード埋め込みを実装する

Clock Icon2024.09.29

いわさです。

Amazon QuickSight は外部 Web アプリケーションにダッシュボードやコンソールを埋め込むことが出来るのですが、パブリックな 1-Click 埋め込み機能以外は API を使って一時的なセッションを張って URL を生成したりとフロントエンドとバックエンドどちらも実装が必要でまぁまぁ面倒です。

そこで、最近 Amplify Gen 2 を使った検証を行うことが多く、フロント+バックエンドAmplify のクイックスタート+αで組み込みダッシュボードを実装出来ると便利かもしれないなと思ったので実装してみることにしました。

やることとしては最終的には React + Vite の QuickStart テンプレートのページへ、QuickSight Embedding SDK を使ってダッシュボードを埋め込みます。
そのために前段として QuickSight の API を実行して埋め込み用 URL を生成する必要があります。
また、そのリクエストとレスポンスをフロントエンドで送受信する必要があるのですが、今回は Lambda を簡単に組み込める Amplify Data に Amplify Function を関連付けします。要は AppSync + Lambda です。

Ob0by9Nn2RfM.png

Amplify Gen2 でクライアントから Lambda からレスポンス取得する

まずはフロントエンドからサーバーサイドの処理を実行したいと思います。
API Gateway + Lambda で実行する感じなのかなと思ったら、本日時点ではまだその機能は提供されていないようで CDK で API Gateway の構成を書いてやる必要があります。

Amplify を使っているので出来れば Amplify Gen2 の標準提供モジュールで済ませたいところです。
今回は以下の Amplify Funtion の初期設定ページに記載されている方法で Amplify Data に組み込みます。サンプルと同様に Query でで関数から値を受け取る形です。

https://docs.amplify.aws/react/build-a-backend/functions/set-up-function/

関数を用意してスキーマに紐づけるだけです。

amplify/functions/quicksight-embed/resource.ts
import { defineFunction } from '@aws-amplify/backend';

export const quicksightEmbed = defineFunction({
  name: 'quicksight-embed',
  entry: './handler.ts',
});
amplify/functions/quicksight-embed/handler.ts
import type { Schema } from '../../data/resource';

export const handler: Schema["quicksightEmbed"]["functionHandler"] = async (event) => {
  return "hoge dummy";
};
amplify/data/resource.ts
import { type ClientSchema, a, defineData } from "@aws-amplify/backend";
import { quicksightEmbed } from "../functions/quicksight-embed/resource";

const schema = a.schema({
  Hoge: a
    .model({
      HogeContent: a.string(),
      HogeNum: a.integer()
    })
    .authorization((allow) => [allow.owner().identityClaim('custom:tenant_id')]),
  quicksightEmbed: a
    .query()
    .returns(a.string())
    .authorization((allow) => [allow.authenticated()])
    .handler(a.handler.function(quicksightEmbed)),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "userPool",
    apiKeyAuthorizationMode: {
      expiresInDays: 30,
    },
  },
});

これで、フロントエンドから Query してやることで Lambda 関数から値を受け取れるようになりました。

Lambda で QuickSight API の GenerateEmbedUrlForRegisteredUser を実行する

続いて、その Lambda 関数で返却する値を動的なものにします。
前提として QuickSight 側で適当なダッシュボードを作成済みです。そのため次の記事のように QuickSight の API を実行して埋め込み用の URL を取得します。

https://dev.classmethod.jp/articles/quicksight-embed-console-new-api/

今回は匿名ユーザーでのセッション作成ではなく、ユーザーベースでの埋込取得です。
Lambda から QuickSight SDK を使ってGenerateEmbedUrlForRegisteredUserを実行します。

npm install @aws-sdk/client-quicksight
amplify/functions/quicksight-embed/handler.ts
import type { Schema } from '../../data/resource';
import { GenerateEmbedUrlForRegisteredUserCommand, QuickSightClient } from "@aws-sdk/client-quicksight";

export const handler: Schema["quicksightEmbed"]["functionHandler"] = async (event) => {

    const client = new QuickSightClient({ region: "ap-northeast-1" });
    const response = await client.send(new GenerateEmbedUrlForRegisteredUserCommand({
        AwsAccountId: "123456789012",
        SessionLifetimeInMinutes: 600,
        UserArn: "arn:aws:quicksight:ap-northeast-1:123456789012:user/default/hoge.fuga/hoge.piyo",
        ExperienceConfiguration: {
            Dashboard: {
                InitialDashboardId: "3e6e631b-7f3f-4eaf-8d6d-8f02888ca1c6"
            }
        },
        AllowedDomains: [
            "http://localhost:5173"
        ]
    }))
  return response.EmbedUrl ? response.EmbedUrl : "hoge dummy";
};

なお、今回はローカル実行を行うために AllowedDomains パラメータも指定しています。

https://dev.classmethod.jp/articles/quicksight-embed-allow-domains-http/

そして、このままだと API 実行には実は失敗します。
Lambda 関数から QuickSight API を実行するための権限が必要です。
本日時点で Amplify 標準のリソース以外に対する権限を設定するにはバックエンド構成の Lambda に対し直接ポリシーを追加してやる必要があります。

amplify/backend.ts
import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { data } from './data/resource';
import { quicksightEmbed } from './functions/quicksight-embed/resource';

import * as iam from "aws-cdk-lib/aws-iam"

const backend = defineBackend({
  auth,
  data,
  quicksightEmbed,
});

const statement = new iam.PolicyStatement({
  sid: "AllowHogeQuickSight",
  actions: ["quicksight:GenerateEmbedUrlForRegisteredUser"],
  resources: ["arn:aws:quicksight:ap-northeast-1:123456789012:user/default/hoge.fuga/hoge.piyo"],
})
const quicksightEmbedLambda = backend.quicksightEmbed.resources.lambda;
quicksightEmbedLambda.addToRolePolicy(statement)

React + Vite で QuickSight Embedding SDK を使う

これでフロントエンドがサーバーサイドから URL を取得出来るようになりました。
最後に、QuickSight Embedding SDK を使ってその URL を設定します。

QuickSIght Embedding SDK はこちらです。
公式ドキュメントなどを見ると生の JavaScirpt で実装するサンプルが多いのですが、以下の README.MD の Option 2 を今回は使います。

https://github.com/awslabs/amazon-quicksight-embedding-sdk

npm install amazon-quicksight-embedding-sdk
src/App.tsx
import { Authenticator } from '@aws-amplify/ui-react'
import '@aws-amplify/ui-react/styles.css'
import { useEffect } from "react";
import type { Schema } from "../amplify/data/resource";
import { generateClient } from "aws-amplify/data";

import { createEmbeddingContext, FrameOptions } from 'amazon-quicksight-embedding-sdk';

const client = generateClient<Schema>();

function App() {
  useEffect(() => {
    embedDashboard();
  }, []);

  const embedDashboard = async () => {
    const embeddingContext = await createEmbeddingContext();

    const embedUrl = await client.queries.quicksightEmbed();
    const frameOptions: FrameOptions = {
      url: embedUrl.data ? embedUrl.data : "hoge",
      container: '#hoge-quicksight-container',
    };

    const contentOptions = {
      locale: "js-JP"
    };
    await embeddingContext.embedDashboard(frameOptions, contentOptions);
  }

  return (
    <Authenticator>
      {({ signOut }) => (
        <main>
          <h1>My Hoges</h1>
          <div id="hoge-quicksight-container"></div>
          <button onClick={signOut}>Sign out</button>
        </main>
      )}
    </Authenticator>
  );
}

export default App;

実行してみると、クライアントが AppSync 経由で非同期に埋め込み URL を取得し、SDK を使ってコンテナにダッシュボードを埋め込むことが出来ました。

1ED37369-FC6E-4FBC-A343-DA24CB688ACD.png

さいごに

本日は Amazon Amplify Gen 2 の React + Vite テンプレートで Amazon QuickSight Embedding SDK を使ったダッシュボード埋め込みを実装してみました。

ところどころ実装が雑な部分がありますが、概ね必要な部分については実装出来ていそうです。
Amplify Gen2 の QuickStart から追加で本記事の内容を実施すれば QuickSight ダッシュボードの埋め込みまでは出来る感じです。

色々埋め込みダッシュボードで検証したいことがあるのでこれを使ってみようと思います。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.