iframe を使用した Looker コンテンツの埋め込みは、デベロッパーがウェブ アプリケーションにダッシュボード、Look、Explore を追加する際に使用できる方法の 1 つにすぎません。このチュートリアルでは、デベロッパーが React アプリに Looker 可視化を追加する別の方法を紹介します。このチュートリアルは、React アプリの作成の開始条件に基づいており、Looker 可視化コンポーネントを使用します。
このチュートリアルで扱う手順は次のとおりです。
- Looker からクエリスラッグを取得する
- Looker 可視化コンポーネントを使用して React アプリケーションを作成する
- バックエンド ヘルパー サービスを作成する
- サーバーと React アプリを起動する
Looker からクエリスラッグを取得する
React アプリはこれらの手順に依存しているため、Looker で行う必要があることがいくつかあります。
クエリスラッグを取得する
可視化コンポーネントの支柱として使用するクエリ ID またはスラッグが必要です。こちらの記事では、探索 URL からクエリ スラグを取得する方法について説明します。別の例については、Looker のドキュメントをご覧ください。
Looker インスタンスで CORS を構成する
クロスオリジン リソース シェアリング(CORS)は、埋め込みと同じドメイン許可リストによって制御されます。
詳細については、署名付き埋め込みのドキュメント ページをご覧ください。
- Looker インスタンスで [管理者] > [プラットフォーム埋め込み] に移動します。これには管理者権限が必要です。
- React アプリは、デフォルトでは
http://localhost:3000
で実行されます。このアドレスを埋め込みドメイン許可リストに追加すると、アプリからのリクエストを許可し、同じアドレスを使用してリクエストに応答するよう Looker に指示できます。アプリは Looker インスタンスに API リクエストを送信するため、この手順は必須です。この手順を実施しないと、Looker とアプリ間の通信が行われません。
React アプリケーションを作成する
このデモのフロントエンドは、Create React App を使用してシングルページの React アプリケーションを作成します。デモのルートフォルダ(get-started-viz-components
)で次のコマンドを実行して、アプリを作成して依存関係をインストールします。
npx create-react-app frontend-react cd frontend-react npm i
@looker/visualizations npm i @looker/components @looker/components-data
styled-components
これらのコマンドを実行すると、フォルダ構造は次のようになります。
package.json
ファイルを確認して、react-dom
もインストールされていることを確認します。インストールされていない場合は、npm i react-dom
を実行してインストールします。
このデモの package.json
は次のようになります。
{
"name": "frontend-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"@looker/components": "^4.0.3",
"@looker/components-data": "^1.0.0",
"@looker/sdk": "^22.16.0",
"@looker/sdk-rtl": "^21.4.0",
"@looker/visualizations": "^1.1.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.0",
"@testing-library/user-event": "^12.4.0",
"i": "^0.3.7",
"npm": "^8.19.2",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-scripts": "5.0.1",
"styled-components": "^5.3.6",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
環境変数を構成する
アプリのルート ディレクトリ(./frontend-react
)に .env
ファイルを作成し、次の変数を設定します。
REACT_APP_LOOKER_API_HOST=https://your-looker-instance.looker.com
REACT_APP_BACKEND_SERVER=http://localhost:3001/
REACT_APP_BACKEND_SERVER
は、アクセス トークンを抽出する Looker への API 呼び出しを行うために使用するバックエンド ヘルパー サービスのアドレスです。
REACT_APP_LOOKER_API_HOST
は、React アプリから API リクエストを受信する Looker インスタンスのアドレスです。
クライアント サイド SDK を初期化する
React アプリは SDK を使用して、Looker サーバーに API リクエストを行います。これはフロントエンドで行われるため、次のヘルパーを使用して sdk
を初期化できます。
import { Looker40SDK } from '@looker/sdk'
import {
AuthToken,
AuthSession,
BrowserTransport,
DefaultSettings,
} from '@looker/sdk-rtl'
class SDKSession extends AuthSession {
// This is a placeholder for the fetchToken function.
// It is modified to make it useful later.
async fetchToken() {
return fetch('')
}
activeToken = new AuthToken()
constructor(settings, transport) {
super(settings, transport || new BrowserTransport(settings))
}
// This function checks to see if the user is already authenticated
isAuthenticated() {
const token = this.activeToken
if (!(token && token.access_token)) return false
return token.isActive()
}
// This function gets the current token or fetches a new one if necessary
async getToken() {
if (!this.isAuthenticated()) {
const token = await this.fetchToken()
const res = await token.json()
this.activeToken.setToken(res.user_token)
}
return this.activeToken
}
// This function authenticates a user, which involves getting a new token
// It returns a modified object with a new authorization header.
async authenticate(props) {
const token = await this.getToken()
if (token && token.access_token) {
props.mode = 'cors'
delete props.credentials
props.headers = {
...props.headers,
Authorization: `Bearer ${this.activeToken.access_token}`,
}
}
return props
}
}
// This class sets the fetchToken to use the 'real' address of the backend server.
class SDKSessionEmbed extends SDKSession {
async fetchToken() {
return fetch(`${process.env.REACT_APP_BACKEND_SERVER}`)
}
}
// This creates a new session with the 'real' address of the backend server.
const session = new SDKSessionEmbed({
...DefaultSettings,
base_url: process.env.REACT_APP_LOOKER_API_HOST,
})
// This exports the SDK with the authenticated session
export const sdk = new Looker40SDK(session)
可視化をアプリに埋め込む
可視化のクエリスラッグ(この例では Jlm4YHPeT3lLGA9UtHjZcA
)が完了し、sdk
オブジェクトがインスタンス化されました。次のステップでは、Looker 可視化コンポーネントを使用して可視化をアプリに埋め込みます。
import { sdk } from '../src/helpers/CorsSession'
import { Query, Visualization } from '@looker/visualizations'
import { DataProvider } from '@looker/components-data'
import { ComponentsProvider } from '@looker/components'
function App() {
return (
<>
<h1>Get started with Looker visualization components</h1>
<ComponentsProvider>
<DataProvider sdk={sdk}>
{/* Change this query slug to match your query slug */}
<Query query="Jlm4YHPeT3lLGA9UtHjZcA">
<Visualization />
</Query>
</DataProvider>
</ComponentsProvider>
</>
)
}
export default App
フロントエンドの準備が完了しました。コンポーネントの追加やアプリのスタイル追加など、さまざまなことが可能です。
バックエンド ヘルパー サービスを作成する
最後のステップは、フロントエンドからの呼び出しを受信するバックエンド ヘルパー サービスを構築し、Looker-Node SDK を使用してユーザーを認証し、アクセス トークンを抽出してフロントエンドに送り返します。
シンプルにするため、1 つのエンドポイントを持つ Node サーバーを構築します。サーバーは、express
、cors
、@looker/sdk-node
の依存関係を使用します。ルートフォルダ(get-started-viz-components
)から次のコマンドを実行できます。
mkdir backend-node
cd backend-node
npm init -y
npm i express cors @looker/sdk-node
バックエンドから SDK を認証するには、looker.ini
ファイルを使用します。ファイルにデータを入力する方法について詳しくは、SDK-Node ページをご覧ください。これらのコマンドを実行すると、フォルダ構造は次のようになります。
package.json
は次のようになります。
{
"name": "looker-embed-backend",
"version": "1.0.0",
"description": "Backend helper service for getting started with Looker Viz components",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"author": "Looker",
"license": "Apache-2.0",
"dependencies": {
"@looker/sdk-node": "^22.16.0",
"cors": "^2.8.5",
"express": "^4.18.2"
}
}
次に、このコードを新しい server.js
ファイルに追加します。
const cors = require('cors')
const express = require('express')
const { LookerNodeSDK } = require('@looker/sdk-node')
const port = 3001
const app = express()
// The following init40 method will authenticate using
// the looker.ini file
const sdk = LookerNodeSDK.init40()
app.use(
cors({
origin: '*',
})
)
app.use(express.json())
app.get('/', async (req, res) => {
const userId = await sdk.ok(sdk.me('id'))
const accessToken = await sdk.login_user(userId.id)
const user = {
user_token: accessToken.value,
token_last_refreshed: Date.now(),
}
res.json({ ...user })
})
app.listen(port, async () => {
console.log(`Backend Server listening on port ${port}`)
})
サーバーと React アプリを起動する
- ターミナルを開き、
backend-node
フォルダに移動してnpm start
を実行します。 - 2 つ目のターミナルを開き、
frontend-react
フォルダに移動してnpm start
を実行します。 - バックエンド ヘルパー サービスと React アプリが稼働したら、ブラウザを開いて
http://localhost:3000/
に移動し、アプリケーションに埋め込まれた可視化を確認します。