Looker 可视化组件使用入门

当开发者想要向其 Web 应用添加信息中心、Look 或“探索”功能时,使用 iframe 嵌入 Looker 内容只是开发者可以使用的方法之一。本教程介绍了另一种方法,面向希望将 Looker 可视化添加到 React 应用的开发者。本教程基于“创建 React 应用”入门知识,使用 Looker 可视化组件

以下是本教程中介绍的步骤:

  1. 从 Looker 获取查询 Slug
  2. 使用 Looker 可视化组件创建 React 应用
  3. 创建后端帮助程序服务
  4. 启动服务器和 React 应用

从 Looker 获取查询 Slug

由于 React 应用依赖于 Looker,因此您必须在 Looker 中完成一些操作。

获取查询 Slug

您需要查询 ID 或 Slug,它们将用作可视化组件的属性。本文介绍了如何通过探索网址获取查询 Slug。您可以在 Looker 的文档中找到另一个示例。

在 Looker 实例中配置 CORS

跨域资源共享 (CORS) 与嵌入服务由同一网域许可名单控制。

如需了解详情,请参阅签名嵌入文档页面。

  1. 在 Looker 实例上,依次点击管理 > 平台嵌入。这需要管理员权限。
  2. 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

运行这些命令后,您的文件夹结构应如下所示:

一个名为 Frontend 响应的文件夹,其中包含“Node modules”“Public”和“src”文件夹,以及名为 .gitignore、package-lock.json 和 package.json 的文件。

请检查 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)

将可视化图表嵌入应用中

现在,您已经有了可视化图表的查询 Slug(在我们的示例中为 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 对用户进行身份验证,提取其访问令牌,然后将其发送回前端。

为简单起见,我们将构建一个具有一个端点的节点服务器。服务器将使用 expresscors@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 节点页面。运行这些命令后,您的文件夹结构应如下所示:

一个名为 backend-node 的文件夹,其中包含一个名为 node_modules 的文件夹,以及文件 looker.ini、package-lock.json、package.json 和 server.js。

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 init40 method below 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
  • 打开第二个终端,然后前往 frontend-react 文件夹并运行 npm start
  • 后端帮助程序服务和 React 应用启动并运行后,您可以打开浏览器并转到 http://localhost:3000/,查看嵌入到应用中的可视化图表。

查看 GitHub 中的代码