Looker 시각화 구성요소 시작하기

iframe을 통해 Looker 콘텐츠를 삽입하는 것은 개발자가 웹 애플리케이션에 대시보드, Look 또는 Explore를 추가하려는 경우 사용할 수 있는 방법 중 하나입니다. 이 튜토리얼에서는 React 앱에 Looker 시각화를 추가하려는 개발자를 위한 또 다른 방법을 제시합니다. 이 튜토리얼은 간단한 React 앱 만들기 스타터를 기반으로 하며 Looker 시각화 구성요소를 사용합니다.

이 튜토리얼에서 다루는 단계는 다음과 같습니다.

  1. Looker에서 쿼리 슬러그 가져오기
  2. Looker 시각화 구성요소로 React 애플리케이션 만들기
  3. 백엔드 도우미 서비스 만들기

Looker에서 쿼리 슬러그 가져오기

React 앱은 이러한 기능을 사용하기 때문에 Looker에서 해야 할 작업이 거의 없습니다.

쿼리 슬러그 가져오기

시각화 구성요소의 속성으로 사용되는 쿼리 ID 또는 슬러그가 필요합니다. 이 도움말에서는 탐색 URL에서 쿼리 슬러그를 가져오는 방법을 설명합니다. Looker 문서에서 또 다른 예를 확인할 수 있습니다.

Looker 인스턴스에서 CORS 구성

교차 출처 리소스 공유 (CORS)는 삽입과 동일한 도메인 허용 목록에 의해 제어됩니다.

이 방법은 싱글 사인온 (SSO) 삽입 문서 페이지에 자세히 설명되어 있습니다.

  1. Looker 인스턴스에서 관리 > 플랫폼 삽입으로 이동합니다. 이 경우 관리자 권한이 필요합니다.
  2. React 앱은 기본적으로 http://localhost:3000에서 실행됩니다. 이 주소를 삽입된 도메인 허용 목록에 추가하면 Looker에서 앱의 요청을 허용하고 동일한 주소를 통해 요청에 응답하도록 합니다. 이 단계는 앱에서 Looker 인스턴스에 API를 요청합니다. 그렇지 않으면 Looker와 앱 간에 통신이 발생하지 않으므로 이 단계는 필수입니다.

React 애플리케이션 만들기

이 데모의 프런트엔드는 React 앱 만들기를 사용하여 단일 페이지 React 애플리케이션을 만듭니다. demo의 루트 폴더(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 used above
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를 사용하여 사용자를 인증하고, 액세스 토큰을 추출한 다음 프런트엔드로 다시 보내는 것입니다.

편의상 엔드포인트 하나를 포함하는 노드 서버를 구축해 보겠습니다. 서버는 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 노드 페이지에서 파일을 채우는 방법을 자세히 알아볼 수 있습니다. 이러한 명령어를 실행하면 폴더 구조는 다음과 같습니다.

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를 실행합니다.
  • 백엔드 도우미 서비스와 반응 앱이 실행되면 브라우저를 열고 http://localhost:3000/로 이동하여 애플리케이션에 삽입된 시각화를 확인할 수 있습니다.

GitHub에서 코드 보기