본문 바로가기

엉터리 개발 이야기/Superset

[Superset] REST API 호출하여 Chart 그리기

반응형

Superset은 여러 가지의 SQL 언어로된 DB 에서 데이터를 가져와 시각화 한다.

야메로, REST API 호출해서 리턴된 데이터로 시각화를 해보자.


우선 Distribution Horizontal Bar Chart에 추가 예시(나머지 차트도 chart data 만 잘 구성해주면 된다.)


1. Chart Explorer 왼쪽 패널에 REST API 호출 할 수 있는 내용을 넣는다.

visTypes.js

1.1 sections 에 restapi 추가((나중에 다른 type에서도 활용 할 수 있도록 sections에 추가)

export const sections = {
...
,
restapi: {
label: t('REST API'),
expanded: false,
controlSetRows: [
[
'use_rest_api'],
['rest_api_url'],
['x_key'],
['y_key'],
]
}
,

};

1.2 distribution bar chart에 restapi 추가 - sections.restapi, 만 추가 하면된다.

dist_bar_horizontal: {
label: t('Distribution - Horizontal Bar Chart'),
showOnExplore: true,
controlPanelSections: [
sections.restapi,
{
label: t('Query'),
expanded: true,
controlSetRows: [
['metrics'],
['groupby'],
['columns'],
['row_limit'],
['contribution'],
['stacked_metrics'],
],
},
...


controls.jsx

control를 추가해준다. use_rest_api, rest_api_url, x_key, y_key 를 추가한다.

use_rest_api: {
type: 'CheckboxControl',
label: t('Using REST API'),
default: false,
description: ('Use REST API'),
},

rest_api_url: {
type: 'TextControl',
label: t('ex)http://127.0.0.1/getUserList'),
default: '',
},

x_key: {
type: 'TextControl',
label: t('Series Name'),
default: '',
},

y_key: {
type: 'TextControl',
label: t('Value Name'),
default: '',
},


추가해주고 Build 해주면 왼쪽에 REST API Section 이 나온다.


Using REST API 가 체크 되었을 경우 DB에서 값을 가져오지 않고 처리 되도록 한다.

여기서부턴 예외처리 없이 ..무조건 동작한다고 가정하고 만들었다...(추후, 수정 필요)


core.py

rest api 를 사용할 경우 기존 viz_obj.get_payload() 대신 다른 함수를 호출하도록 해준다.

그리고 export 시에도 동작하도록 구분해준다.

if csv:
is_rest_api = form_data.get('use_rest_api')
if is_rest_api:
return CsvResponse(
viz_obj.get_csv_for_rest_api(),
status=200,
headers=generate_download_headers('csv'),
mimetype='application/csv')
else:
return CsvResponse(
viz_obj.get_csv(),
status=200,
headers=generate_download_headers('csv'),
mimetype='application/csv')

if query:
return self.get_query_string_response(viz_obj)

try:
is_rest_api = form_data.get('use_rest_api')
if is_rest_api:
payload = viz_obj.get_rest_api_data()
else:
payload = viz_obj.get_payload()
except SupersetException as se:
logging.exception(se)
return json_error_response(utils.error_msg_from_exception(se),
status=se.status)
except Exception as e:
logging.exception(e)
return json_error_response(utils.error_msg_from_exception(e))

status = 200
if (
payload.get('status') == QueryStatus.FAILED or
payload.get('error') is not None
):
status = 400
if is_rest_api:
return json_success(viz_obj.json_dumps(payload), status=status)
else:
return json_success(viz_obj.json_dumps(payload), status=status)

(중복코드가 많다..정리 필요)


viz.py

class BaseViz 에 get_rest_api_data() 를 추가한다. url을 호출하여 json 형태로 받아온다.

payload는 임시적으로 넣었다.

def get_rest_api_data(self):
using_rest_api = self.form_data.get('use_rest_api')
rest_api_url = self.form_data.get('rest_api_url')

http = urllib3.PoolManager()

json_data = json.loads(r.data.decode('utf-8'))

payload = {'cache_key': None,
'cached_dttm': None,
'cache_timeout': None,
'df': None,
'error': None,
'form_data': self.form_data,
'is_cached': None,
'query': None,
'status': 200,
'stacktrace': None,
'rowcount': 0
}

if json_data is None or len(json_data) == 1:
payload['data'] = 'No Data'
payload['error'] = 'No data'
else:
payload['data'] = self.convert_rest_api_data(json_data)
payload['json_data'] = json_data

return payload


각 type에 convert_rest_api_data를 추가해준다.

def convert_rest_api_data(self, json_data):
x_key = self.form_data.get('x_key')
y_key = self.form_data.get('y_key')

chart_data = []
values = []


for v in json_data:
values.append({'x': v[x_key], 'y': v[y_key]})



d = {
'key': y_key,
'values': values,
}

chart_data.append(d)

return chart_data


예를 들어, rest_api 호출 결과가 아래와 같다면 x에는 name값을 , y에는 count 값을 입력해준다.

[
{
"name": "Seoul",
"count": "10"
},
{
"name": "InCheon",
"count": "15"
},
{
"name": "Suwon",
"count": "50"
},
{
"name": "Busan",
"count": "5"
},
{
"name": "Daegu",
"count": "25"
}
]


이렇게 하면 끝이다.

여기에 sort, filter 기능을 추가하면 더욱 더 강력하게 사용할 수 있다.


반응형