-
Notifications
You must be signed in to change notification settings - Fork 14.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[table] feat: REST API #9034
[table] feat: REST API #9034
Conversation
superset/connectors/sqla/api.py
Outdated
logger = logging.getLogger(__name__) | ||
|
||
|
||
def validate_database(value): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: value
->db_id
. The name value
is a bit ambiguous
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was just following def __call__(self, value)
from marshmallow, but yes, I'll change that
superset/connectors/sqla/api.py
Outdated
|
||
@validates_schema | ||
def validate_schema(self, data: Dict): # pylint: disable=no-self-use | ||
validate_table_uniqueness(data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mixing API schema validation and business logic/db validation feels like a bad pattern here. Marshmallow should be concerned with keeping requests in/out of the API consistent, whereas data access rules and/or auth should live inside the ViewController.
One other interesting side note - these checks could potentially trigger BEFORE auth validation happens, which could lead to leakage (a user without rights to a DB for instance could phish around for DB names which would trigger these replies if auth logic happened downstream of this)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, good catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The schema validation is debatable, since we are only performing basic data validation (does the relation exist?, is the fields unique?). Yet I have mixed feelings about it. The other approach would use pre_
, post_
hooks. Note that using marshmallow validation gives us proper error messages for free.
It's not possible for the validation to trigger before any auth validation. Since this is done at the view decorator level. Yet, it's certainly a good point since it's possible further down the road for mashmallow validation to perform some kind of data authorization.
I would say this is a key issue. Marshmallow data validation is really useful, but has some constrains, and may easily force unnecessary db round trips (notice the use of the flask g on this case, that I'm not a big fan). We can rollback this pattern (it already implemented on previous new API PR's) and rollback to using pre_
, post_
hooks that can call specific business logic API outside of the view scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's one or the other. I think marshmallow validation is great for validating the shape of the request. I do not think that marshmallow should be running database queries. My recommendation would be for the validation/auth logic to look something like:
- Can the user access the route? If yes, continue, if no 403
- Run marshmallow validation to validate the shape of the request. If OK, continue, if not 400
- Look up the resource being modified. Can the user modify it? If so, continue, if not 403
- Attempt the resource modification.
I think that can be accomplished via some combination of marshmallow and pre_ and post_ hooks, but you're the expert :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can also become a security issue quite easily. If we are doing data validation inside of marshmallow schemas, an attacker could (potentially) use validation errors to gather information about a resource that they should not have access to. The schema must be very carefully written and thoroughly tested to prevent this. Much better to separate schema validation/resource checks as described by @willbarrett
I am also trying to add REST API for table 9118. It is good to know we've already been working on the same feature. Do we have a plan on when this PR will be merged into master? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor non-blocking comments.
@@ -21,7 +21,7 @@ croniter==0.3.31 | |||
cryptography==2.8 | |||
decorator==4.4.1 # via retry | |||
defusedxml==0.6.0 # via python3-openid | |||
flask-appbuilder==2.2.2 | |||
flask-appbuilder==2.2.3rc5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs a rebase
include_route_methods = RouteMethod.REST_MODEL_VIEW_CRUD_SET | {RouteMethod.RELATED} | ||
openapi_spec_tag = "Datasets" | ||
|
||
list_columns = ["metric_name", "verbose_name", "metric_type"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"type": "VARCHAR", | ||
"groupby": False, | ||
"filterable": True, | ||
"expression": "col expression", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: perhaps put some ANSI SQL here: case when 1 = 1 then 'abc' else 'qwerty' end
verbose_name: str = "", | ||
description: str = "", | ||
type: str = "", | ||
groupby: bool = True, | ||
filterable: bool = True, | ||
is_dttm: bool = True, | ||
expression: str = "", | ||
python_date_format: str = "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some reason the str
s aren't Optional[str] = None
? In the datamodel these seem to be nullable.
Replaced by #9268 |
CATEGORY
SUMMARY
Following CRUD MVC deprecation. CRUD REST API for tables
ADDITIONAL INFORMATION
REVIEWERS
@nytai