Skip to content
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

Move API endpoints from the config file to the code #118

Merged
merged 7 commits into from
May 23, 2019

Conversation

tommydeboer
Copy link
Collaborator

@tommydeboer tommydeboer commented Apr 18, 2019

Depends on: #117 Error when the config contains (old) unknown properties

This PR is a preparation for the compatibility framework

After this PR you can no longer override the API endpoints in the config file, so running integration tests against a MOLGENIS 8 will cause some tests (involving groups) to fail.

Checklist

  • Functionality works & meets specifications
  • Code reviewed
  • Code unit/system tested
  • User documentation updated
  • Test plan template updated
  • Clean commits
  • Added Feature/Fix to release notes

@tommydeboer tommydeboer changed the title Move API endpoints from the config file to the code base Move API endpoints from the config file to the code Apr 18, 2019
@tommydeboer tommydeboer mentioned this pull request Apr 18, 2019
7 tasks
Copy link
Contributor

@marikaris marikaris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want to move this from the config? I thought we found it elegant that when the name of an API in molgenis is changed, it can still be used, unless functionality of the API was changed of course.

Copy link
Contributor

@dennishendriksen dennishendriksen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect most encoding issues could be prevented by using the MOLGENIS Python API client.


@endpoint
def member(group_name):
return 'api/plugin/security/group/{}/member/'.format(group_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

group_name should be encoded (something like https://stackoverflow.com/a/6431284)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tommydeboer group name should still be encoded?

@@ -98,15 +98,15 @@ def _delete_package_contents(args):

def _delete_entity_types_in_package(package_id):
response = client.get(
config.api('rest2') + ResourceType.ENTITY_TYPE.get_entity_id() + '?attrs=id&q=package==' + package_id)
api.rest2() + ResourceType.ENTITY_TYPE.get_entity_id() + '?attrs=id&q=package==' + package_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entity_ids = [entity_type['id'] for entity_type in response.json()['items']]
if len(entity_ids) > 0:
_delete_rows(ResourceType.ENTITY_TYPE.get_entity_id(), entity_ids)


def _delete_packages_in_package(package_id):
response = client.get(
config.api('rest2') + ResourceType.PACKAGE.get_entity_id() + '?attrs=id&q=parent==' + package_id)
api.rest2() + ResourceType.PACKAGE.get_entity_id() + '?attrs=id&q=parent==' + package_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see previous comment on encoding



def _delete_rows(entity_type, rows):
url = '{}{}'.format(config.api('rest2'), entity_type)
url = '{}{}'.format(api.rest2(), entity_type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entity_type needs to be encoded

@@ -66,7 +66,7 @@ def set_(args):
io.start(
'Updating {} of {} settings to {}'.format(highlight(args.setting), highlight(args.type), highlight(args.value)))
row = _get_row_id(entity)
url = '{}{}/{}/{}'.format(config.api('rest1'), entity, row, args.setting)
url = '{}{}/{}/{}'.format(api.rest1(), entity, row, args.setting)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL components should be encoded

@@ -53,14 +53,14 @@ def detect_resource_type(resource_id, types: List[ResourceType]):
def resource_exists(resource_id, resource_type):
log.debug('Checking if %s %s exists' % (resource_type.get_label(), resource_id))
query = '?q={}=={}'.format(resource_type.get_identifying_attribute(), resource_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encoding issues (see previous comments)

@@ -53,14 +53,14 @@ def detect_resource_type(resource_id, types: List[ResourceType]):
def resource_exists(resource_id, resource_type):
log.debug('Checking if %s %s exists' % (resource_type.get_label(), resource_id))
query = '?q={}=={}'.format(resource_type.get_identifying_attribute(), resource_id)
response = get(config.api('rest2') + resource_type.get_entity_id() + query)
response = get(api.rest2() + resource_type.get_entity_id() + query)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resource_type.get_entity_id() should be encoded

@@ -53,14 +53,14 @@ def detect_resource_type(resource_id, types: List[ResourceType]):
def resource_exists(resource_id, resource_type):
log.debug('Checking if %s %s exists' % (resource_type.get_label(), resource_id))
query = '?q={}=={}'.format(resource_type.get_identifying_attribute(), resource_id)
response = get(config.api('rest2') + resource_type.get_entity_id() + query)
response = get(api.rest2() + resource_type.get_entity_id() + query)
return int(response.json()['total']) > 0


def one_resource_exists(resources, resource_type):
log.debug('Checking if one of [{}] exists in [{}]'.format(','.join(resources), resource_type.get_label()))
query = '?q={}=in=({})'.format(resource_type.get_identifying_attribute(), ','.join(resources))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encoded issues (see previous comments)

return int(response.json()['total']) > 0


def one_resource_exists(resources, resource_type):
log.debug('Checking if one of [{}] exists in [{}]'.format(','.join(resources), resource_type.get_label()))
query = '?q={}=in=({})'.format(resource_type.get_identifying_attribute(), ','.join(resources))
response = get(config.api('rest2') + resource_type.get_entity_id() + query)
response = get(api.rest2() + resource_type.get_entity_id() + query)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encoding issues (see previous comments)

tests/unit/version/molgenis_version_test.py Show resolved Hide resolved
@dennishendriksen
Copy link
Contributor

@tommydeboer could you address the comment of @marikaris?

@tommydeboer
Copy link
Collaborator Author

@dennishendriksen @marikaris

Do we really want to move this from the config? I thought we found it elegant that when the name of an API in molgenis is changed, it can still be used, unless functionality of the API was changed of course.

Moving the location of these strings to the code makes it easier to switch between them based on versions (see #119). If we would want to do this in the config we would have to invent new keys for each endpoint (group7 and group8 for example) and add extra code for figuring out which key to use when. This PR is based on the idea that APIs won't constantly change names or move to another location. Even if that happens, it's a matter of adding one method in the code and doing a patch release. I have thought about also making it possible to override the endpoints in the config, but that seems like another feature of which I don't think it's worth the cost to build it.

@tommydeboer
Copy link
Collaborator Author

@dennishendriksen

I suspect most encoding issues could be prevented by using the MOLGENIS Python API client.

We're not using the Python client (yet), because:

  1. There are a lot of other endpoints being used that are not the REST API
  2. The Python client uses REST API v1 which will be deprecated
  3. Not using it gives us more flexibility of when and how to authenticate
  4. Not using it gives us a generalised way to handle all requests to MOLGENIS (+ error handling)

I think we can fix the encoding issues in the molgenis_client module.

@marikaris
Copy link
Contributor

@dennishendriksen

I suspect most encoding issues could be prevented by using the MOLGENIS Python API client.

We're not using the Python client (yet), because:

  1. There are a lot of other endpoints being used that are not the REST API
  2. The Python client uses REST API v1 which will be deprecated
  3. Not using it gives us more flexibility of when and how to authenticate
  4. Not using it gives us a generalised way to handle all requests to MOLGENIS (+ error handling)

I think we can fix the encoding issues in the molgenis_client module.

@tommydeboer
In the molgenis py client (which soon will be doing get requests over API v2 rather than v1) we use quote_plus from urllib.parse to fix those encoding issues. Maybe we can use that?

@tommydeboer
Copy link
Collaborator Author

@dennishendriksen @marikaris
Concerning the escaping of RSQL values: I couldn't find a (reliable looking) Python library that does this. I've added an issue for this problem (#125) and propose to fix this another time since it is not introduced by this PR.

@tommydeboer tommydeboer mentioned this pull request May 9, 2019
7 tasks
@tommydeboer
Copy link
Collaborator Author

@dennishendriksen
I've added an issue for using the Python REST Client (#126)

Copy link
Contributor

@marikaris marikaris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a few comments, no sure if you should do something with it.


@endpoint
def member(group_name):
return 'api/plugin/security/group/{}/member/'.format(group_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tommydeboer group name should still be encoded?



@command
def add_token(args):
io.start('Adding token %s for user %s' % (highlight(args.token), highlight(args.user)))

user = get(config.api('rest2') + 'sys_sec_User?attrs=id&q=username==%s' % args.user)
user = get(api.rest2('sys_sec_User'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want this tablename hardcoded here?

@@ -173,7 +178,7 @@ def add_token(args):
data = {'User': user_id,
'token': args.token}

post(config.api('rest1') + 'sys_sec_Token', data)
post(api.rest1('sys_sec_Token'), data=data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want this tablename hardcoded here?



def _find_group(role):
io.debug('Fetching groups')
groups = get(config.api('rest2') + 'sys_sec_Group?attrs=name')
groups = get(api.rest2('sys_sec_Group'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want this table name hardcoded here?

query = 'q=extends==sys_set_settings&attrs=~id'
molgenis_settings = _quick_get(entity, query)
molgenis_settings = get(api.rest2('sys_md_EntityType'),
params={
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a hardcoded table name?

return int(response.json()['total']) > 0


def role_exists(rolename):
log.debug('Checking if role %s exists' % rolename)
response = get(config.api('rest2') + 'sys_sec_Role?q=name==' + rolename.upper())
response = get(api.rest2('sys_sec_Role'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded tablename

@@ -30,13 +30,20 @@ def principal_exists(principal_name, principal_type):

def user_exists(username):
log.debug('Checking if user %s exists' % username)
response = get(config.api('rest2') + 'sys_sec_User?q=username==' + username)
response = get(api.rest2('sys_sec_User'),
params={
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hardcoded tablename

@marikaris marikaris merged commit c98087c into molgenis:master May 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants