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到项目之中。