Skip to content

Commit

Permalink
chore: Add OpenAPI docs to /api/v1/chart/data EP (#9556)
Browse files Browse the repository at this point in the history
* Add OpenAPI docs to /api/v1/chart/data EP

* Add missing fields to QueryObject, fix linting and unit test errors

* Fix unit test errors

* abc

* Fix errors uncovered by schema validation and add unit test for invalid payload

* Add schema for response

* Remove unnecessary pylint disable
  • Loading branch information
villebro committed Apr 17, 2020
1 parent 427d2a0 commit 8e439b1
Show file tree
Hide file tree
Showing 13 changed files with 695 additions and 148 deletions.
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ combine_as_imports = true
include_trailing_comma = true
line_length = 88
known_first_party = superset
known_third_party =alembic,backoff,bleach,celery,click,colorama,contextlib2,croniter,cryptography,dateutil,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,geohash,geopy,humanize,isodate,jinja2,markdown,markupsafe,marshmallow,msgpack,numpy,pandas,parsedatetime,pathlib2,polyline,prison,pyarrow,pyhive,pytz,retry,selenium,setuptools,simplejson,sphinx_rtd_theme,sqlalchemy,sqlalchemy_utils,sqlparse,werkzeug,wtforms,wtforms_json,yaml
known_third_party =alembic,apispec,backoff,bleach,celery,click,colorama,contextlib2,croniter,cryptography,dateutil,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,geohash,geopy,humanize,isodate,jinja2,markdown,markupsafe,marshmallow,msgpack,numpy,pandas,parsedatetime,pathlib2,polyline,prison,pyarrow,pyhive,pytz,retry,selenium,setuptools,simplejson,sphinx_rtd_theme,sqlalchemy,sqlalchemy_utils,sqlparse,werkzeug,wtforms,wtforms_json,yaml
multi_line_output = 3
order_by_type = false

Expand Down
84 changes: 22 additions & 62 deletions superset/charts/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
from typing import Any, Dict

import simplejson
from apispec import APISpec
from flask import g, make_response, redirect, request, Response, url_for
from flask_appbuilder.api import expose, protect, rison, safe
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_babel import ngettext
from flask_babel import gettext as _, ngettext
from werkzeug.wrappers import Response as WerkzeugResponse
from werkzeug.wsgi import FileWrapper

Expand All @@ -41,12 +42,13 @@
from superset.charts.commands.update import UpdateChartCommand
from superset.charts.filters import ChartFilter, ChartNameOrDescriptionFilter
from superset.charts.schemas import (
CHART_DATA_SCHEMAS,
ChartDataQueryContextSchema,
ChartPostSchema,
ChartPutSchema,
get_delete_ids_schema,
thumbnail_query_schema,
)
from superset.common.query_context import QueryContext
from superset.constants import RouteMethod
from superset.exceptions import SupersetSecurityException
from superset.extensions import event_logger, security_manager
Expand Down Expand Up @@ -381,74 +383,21 @@ def data(self) -> Response:
Takes a query context constructed in the client and returns payload data
response for the given query.
requestBody:
description: Query context schema
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:
type: object
properties:
datasource:
type: object
description: The datasource where the query will run
properties:
id:
type: integer
type:
type: string
queries:
type: array
items:
type: object
properties:
granularity:
type: string
groupby:
type: array
items:
type: string
metrics:
type: array
items:
type: object
filters:
type: array
items:
type: string
row_limit:
type: integer
$ref: "#/components/schemas/ChartDataQueryContextSchema"
responses:
200:
description: Query result
content:
application/json:
schema:
type: array
items:
type: object
properties:
cache_key:
type: string
cached_dttm:
type: string
cache_timeout:
type: integer
error:
type: string
is_cached:
type: boolean
query:
type: string
status:
type: string
stacktrace:
type: string
rowcount:
type: integer
data:
type: array
items:
type: object
$ref: "#/components/schemas/ChartDataResponseSchema"
400:
$ref: '#/components/responses/400'
500:
Expand All @@ -457,7 +406,11 @@ def data(self) -> Response:
if not request.is_json:
return self.response_400(message="Request is not JSON")
try:
query_context = QueryContext(**request.json)
query_context, errors = ChartDataQueryContextSchema().load(request.json)
if errors:
return self.response_400(
message=_("Request is incorrect: %(error)s", error=errors)
)
except KeyError:
return self.response_400(message="Request is incorrect")
try:
Expand All @@ -466,7 +419,7 @@ def data(self) -> Response:
return self.response_401()
payload_json = query_context.get_payload()
response_data = simplejson.dumps(
payload_json, default=json_int_dttm_ser, ignore_nan=True
{"result": payload_json}, default=json_int_dttm_ser, ignore_nan=True
)
resp = make_response(response_data, 200)
resp.headers["Content-Type"] = "application/json; charset=utf-8"
Expand Down Expand Up @@ -533,3 +486,10 @@ def thumbnail(
return Response(
FileWrapper(screenshot), mimetype="image/png", direct_passthrough=True
)

def add_apispec_components(self, api_spec: APISpec) -> None:
for chart_type in CHART_DATA_SCHEMAS:
api_spec.components.schema(
chart_type.__name__, schema=chart_type,
)
super().add_apispec_components(api_spec)
Loading

0 comments on commit 8e439b1

Please sign in to comment.