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

iframe을 사용한 Looker 콘텐츠 임베딩은 개발자가 웹 애플리케이션에 대시보드, Look 또는 Explore를 추가하려고 할 때 사용할 수 있는 방법 중 하나에 불과합니다. 이 튜토리얼에서는 React 앱에 Looker 시각화를 추가하려는 개발자를 위한 또 다른 방법을 제공합니다. 이 튜토리얼은 React 앱 만들기 시작 가이드를 기반으로 하며 Looker 시각화 구성요소를 사용합니다.

이 튜토리얼은 다음 단계에 따라 진행됩니다.

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

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

Looker에서 수행해야 하는 몇 가지 작업이 있습니다. React 앱이 이에 따라 달라지기 때문입니다.

쿼리 슬러그 가져오기

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

Looker 인스턴스에서 CORS 구성

교차 출처 리소스 공유(CORS)는 임베딩과 동일한 도메인 허용 목록에서 제어됩니다.

자세한 내용은 서명된 임베딩 문서 페이지를 참조하세요.

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

React 애플리케이션 만들기

이 데모의 프런트엔드는 React 앱 만들기를 사용하여 단일 페이지 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

이러한 명령어를 실행하면 폴더 구조가 다음과 같이 표시됩니다.

폴더 노드 모듈, 공개, 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는 API 호출을 Looker에 보내 액세스 토큰을 추출하는 데 사용하는 백엔드 도우미 서비스의 주소입니다.

REACT_APP_LOOKER_API_HOST는 React 앱에서 API 요청을 수신하는 Looker 인스턴스의 주소입니다.

클라이언트 측 SDK 초기화

React 앱은 SDK를 사용하여 API 요청을 Looker 서버에 보냅니다. 이 작업은 프런트엔드에서 수행되므로 다음 도우미를 사용하여 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를 사용하여 사용자를 인증하고 액세스 토큰을 추출한 후 프런트엔드로 다시 보내는 것입니다.

편의상 엔드포인트 하나로 노드 서버를 빌드해 보겠습니다. 서버는 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 페이지를 참조하세요. 이러한 명령어를 실행하면 폴더 구조가 다음과 같이 표시됩니다.

node_modules라는 폴더와 looker.ini, package-lock.json, package.json, server.js 파일이 포함된 backend-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 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의 코드 참조