Superset如何新增api

本章我们讲述下,如何在Superset框架中增加API,本章的内容相比较下比较简单,也是关于框架层面的一些使用介绍,涉及到的源码拆解较少。如果能够在实际开发使用中帮助到读者,就算本章完美达成目标了。

那么回到正题,在Superset中,我们所有暴露的接口都是存放在框架的api和view类中的。

这里我们拿一个接口进行拆解,以data/api.py中的接口为例

@expose(“/data”, methods=[“POST”])

@protect()

@statsd_metrics

@event_logger.log_this_with_context(

action=lambda self, *args, **kwargs: f”{self.__class__.__name__}.data”,

log_to_statsd=False,

)

def data(self) -> Response:

“””

Takes a query context constructed in the client and returns payload

data response for the given query.

post:

description: >-

Takes a query context constructed in the client and returns payload data

response for the given query.

requestBody:

description: >-

A query context consists of a datasource from which to fetch data

and one or many query objects.

required: true

content:

application/json:

schema:

$ref: “#/components/schemas/ChartDataQueryContextSchema”

responses:

200:

description: Query result

content:

application/json:

schema:

$ref: “#/components/schemas/ChartDataResponseSchema”

202:

description: Async job details

content:

application/json:

schema:

$ref: “#/components/schemas/ChartDataAsyncResponseSchema”

400:

$ref: ‘#/components/responses/400’

401:

$ref: ‘#/components/responses/401’

500:

$ref: ‘#/components/responses/500’

“””

json_body = None

if request.is_json:

json_body = request.json

elif request.form.get(“form_data”):

# CSV export submits regular form data

try:

json_body = json.loads(request.form[“form_data”])

except (TypeError, json.JSONDecodeError):

pass

if json_body is None:

return self.response_400(message=_(“Request is not JSON”))

try:

query_context = self._create_query_context_from_form(json_body)

command = ChartDataCommand(query_context)

command.validate()

except DatasourceNotFound as error:

return self.response_404()

except QueryObjectValidationError as error:

return self.response_400(message=error.message)

except ValidationError as error:

return self.response_400(

message=_(

“Request is incorrect: %(error)s”, error=error.normalized_messages()

)

)

# TODO: support CSV, SQL query and other non-JSON types

if (

is_feature_enabled(“GLOBAL_ASYNC_QUERIES”)

and query_context.result_format == ChartDataResultFormat.JSON

and query_context.result_type == ChartDataResultType.FULL

):

return self._run_async(json_body, command)

form_data = json_body.get(“form_data”)

return self._get_data_response(

command, form_data=form_data, datasource=query_context.datasource

)

上面首先是expose 注解,这里利用了Flask官方的注解,通过这个注解,从而将接口进行暴露出去。

其次是下面的@protect注解,确定了需要进行权限校验,具体如何进行权限校验,权限的配置,可以参考上一章节。

在之后statsd_metrics用来给接口执行时间进行记录。

@event_logger.log_this_with_context()

这是用来记录日志的注解

默认会记录传入参数。

如果想要记录更多信息,比如一个实体的详细信息,则可以使用函数log_this_with_extra_payload

通过传入一个额外函数,从而记录更多的信息。

接下来的““”注解用来给Swagger声明相关信息。

https://pypi.org/project/flask-swagger/

在返回数据的时候,Superset封装了自己的返回方法

def response_404(self) -> Response:

“””

Helper method for HTTP 404 response

:param message: Error message (str)

:return: HTTP Json response

“””

return self.response(404, **{“message”: “Not found”})

通过统一的self.response()进行返回。

@staticmethod

def response(code: int, **kwargs: Any) -> Response:

“””

Generic HTTP JSON response method

:param code: HTTP code (int)

:param kwargs: Data structure for response (dict)

:return: HTTP Json response

“””

_ret_json = jsonify(kwargs)

resp = make_response(_ret_json, code)

resp.headers[“Content-Type”] = “application/json; charset=utf-8”

return resp

那么上面就是简单的在一个api里面增加一个接口

另一方面,我们还需要看如何在整个Superset中增加一个api类文件

这一个过程其实和我们上一章提到的权限校验中菜单展示有交集。只不过view和api的初始化,位于Superset在启动项目之初,在app_initializer.init_app()中进行初始化的时候,会初始化ctx上下文,在此方法的最后会初始化views

而在此之中会导入相关的view和api

在位于superset.initialization.SupersetAppInitializer中的init_views方法中

将api和view添加进入appbuilder,从而进行访问。

#

# Setup API views

#

appbuilder.add_api(AnnotationRestApi)

appbuilder.add_api(AnnotationLayerRestApi)

appbuilder.add_api(AsyncEventsRestApi)

appbuilder.add_api(AdvancedDataTypeRestApi)

appbuilder.add_api(AvailableDomainsRestApi)

appbuilder.add_api(CacheRestApi)

appbuilder.add_api(ChartRestApi)

appbuilder.add_api(ChartDataRestApi)

appbuilder.add_api(CssTemplateRestApi)

appbuilder.add_api(CurrentUserRestApi)

appbuilder.add_api(DashboardFilterStateRestApi)

appbuilder.add_api(DashboardPermalinkRestApi)

appbuilder.add_api(DashboardRestApi)

appbuilder.add_api(DatabaseRestApi)

appbuilder.add_api(DatasetRestApi)

appbuilder.add_api(DatasetColumnsRestApi)

appbuilder.add_api(DatasetMetricRestApi)

appbuilder.add_api(DatasourceRestApi)

appbuilder.add_api(EmbeddedDashboardRestApi)

appbuilder.add_api(ExploreRestApi)

appbuilder.add_api(ExploreFormDataRestApi)

appbuilder.add_api(ExplorePermalinkRestApi)

appbuilder.add_api(FilterSetRestApi)

appbuilder.add_api(ImportExportRestApi)

appbuilder.add_api(QueryRestApi)

appbuilder.add_api(ReportScheduleRestApi)

appbuilder.add_api(ReportExecutionLogRestApi)

appbuilder.add_api(SavedQueryRestApi)

appbuilder.add_api(SqlLabRestApi)

如果我们有自己的api,那么在这里向appbuilder之中添加即可。

那么本章的内容就到这里了,总结一下,我们简单说了,单个api该如何声明以及如何添加新的api到项目之中。

发表评论

邮箱地址不会被公开。 必填项已用*标注