엉터리 개발 이야기/Superset

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

억삼이 2018. 8. 31. 14:10
반응형

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 기능을 추가하면 더욱 더 강력하게 사용할 수 있다.


반응형