Commit 62403eea by Renzo Lucioni

Extend edX API utility to support retrieval of specific resources

This will be used to retrieve data for the program detail page. Part of ECOM-4415.
parent b3462e5b
......@@ -11,23 +11,25 @@ from openedx.core.lib.token_utils import get_id_token
log = logging.getLogger(__name__)
def get_edx_api_data(api_config, user, resource, querystring=None, cache_key=None):
"""Fetch data from an API using provided API configuration and resource
name.
def get_edx_api_data(api_config, user, resource, resource_id=None, querystring=None, cache_key=None):
"""GET data from an edX REST API.
DRY utility for handling caching and pagination.
Arguments:
api_config (ConfigurationModel): The configuration model governing
interaction with the API.
api_config (ConfigurationModel): The configuration model governing interaction with the API.
user (User): The user to authenticate as when requesting data.
resource(str): Name of the API resource for which data is being
requested.
querystring(dict): Querystring parameters that might be required to
request data.
cache_key(str): Where to cache retrieved data. Omitting this will cause the
cache to be bypassed.
resource (str): Name of the API resource being requested.
Keyword Arguments:
resource_id (int or str): Identifies a specific resource to be retrieved.
querystring (dict): Optional query string parameters.
cache_key (str): Where to cache retrieved data. The cache will be ignored if this is omitted
(neither inspected nor updated).
Returns:
list of dict, representing data returned by the API.
Data returned by the API. When hitting a list endpoint, extracts "results" (list of dict)
returned by DRF-powered APIs.
"""
no_data = []
......@@ -36,30 +38,29 @@ def get_edx_api_data(api_config, user, resource, querystring=None, cache_key=Non
return no_data
if cache_key:
cache_key = '{}.{}'.format(cache_key, resource_id) if resource_id else cache_key
cached = cache.get(cache_key)
if cached is not None:
if cached:
return cached
try:
jwt = get_id_token(user, api_config.OAUTH2_CLIENT_NAME)
api = EdxRestApiClient(api_config.internal_api_url, jwt=jwt)
except Exception: # pylint: disable=broad-except
except: # pylint: disable=bare-except
log.exception('Failed to initialize the %s API client.', api_config.API_NAME)
return no_data
try:
querystring = {} if not querystring else querystring
response = getattr(api, resource).get(**querystring)
results = response.get('results', no_data)
page = 1
next_page = response.get('next', None)
while next_page:
page += 1
querystring['page'] = page
response = getattr(api, resource).get(**querystring)
results += response.get('results', no_data)
next_page = response.get('next', None)
except Exception: # pylint: disable=broad-except
endpoint = getattr(api, resource)
querystring = querystring if querystring else {}
response = endpoint(resource_id).get(**querystring)
if resource_id:
results = response
else:
results = _traverse_pagination(response, endpoint, querystring, no_data)
except: # pylint: disable=bare-except
log.exception('Failed to retrieve data from the %s API.', api_config.API_NAME)
return no_data
......@@ -67,3 +68,22 @@ def get_edx_api_data(api_config, user, resource, querystring=None, cache_key=Non
cache.set(cache_key, results, api_config.cache_ttl)
return results
def _traverse_pagination(response, endpoint, querystring, no_data):
"""Traverse a paginated API response.
Extracts and concatenates "results" (list of dict) returned by DRF-powered APIs.
"""
results = response.get('results', no_data)
page = 1
next_page = response.get('next')
while next_page:
page += 1
querystring['page'] = page
response = endpoint.get(**querystring)
results += response.get('results', no_data)
next_page = response.get('next')
return results
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment