def get_data(): """Get Data resource collection. .. :quickref: Data; Access de-identified survey data. Args: Non-REST, Python API for function has no arguments. Query Args: None Returns: json: Collection for resource. Details: Query de-identified PMA2020 survey data. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/data :name: example-of-collection-data {"Documentation example not available."} """ all_data = data_refined_query(request.args) data = [d.full_json() for d in all_data] return QuerySetApiResult(data, 'json')
def get_country(code): """Country resource entity GET method. .. :quickref: Countries; Access a specific country by its code. Args: code (str): Identification for resource entity. Query Args: None Returns: json: Entity of resource. Details: Access a specific PMA2020 country with publicly available data, by its code. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/countries/CODE :name: example-of-instance-country {"Documentation example not available."} """ lang = request.args.get('_lang') country = Country.query.filter_by(country_code=code).first() json_obj = country.to_json(lang=lang) return QuerySetApiResult(json_obj, 'json')
def get_datum(code): """Get data resource entity. .. :quickref: Data; Access a specific datum by its code. Args: code (str): Identification for resource entity. Query Args: None Returns: json: Entity of resource. Details: Access a specific data record, by its code. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/data/CODE :name: example-of-instance-datum {"Documentation example not available."} """ data = Data.query.filter_by(code=code).first() json_obj = data.full_json() return QuerySetApiResult(json_obj, 'json')
def get_surveys(): """Survey resource collection GET method. .. :quickref: Survey rounds; Get collection of survey rounds. Args: Non-REST, Python API for function has no arguments. Query Args: None Returns: json: Collection for resource. Details: Gets a list of all PMA2020 country survey rounds with publicly available data. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/surveys :name: example-of-collection-surveys { "metadata": { "..." }, "resultSize": 48, "results": [ { "country.id": "GH", "country.label": "Ghana", "country.order": 4, "country.region": "Africa", "country.subregion": "Western Africa", "end_date": "2013-10-01", "id": "PMA2013_GHR1", "order": 101, "pma_code": "GHR1", "round": 1, "start_date": "2013-09-01", "type": "PMA2020", "year": 2013 }, "..." ] } """ # Query by year, country, round # print(request.args) surveys = Survey.query.all() data = [s.full_json() for s in surveys] return QuerySetApiResult(data, 'json')
def get_indicators(): """Get Indicator resource collection. .. :quickref: Indicators; Get collection of available indicators. Args: Non-REST, Python API for function has no arguments. Query Args: None Returns: json: Collection for resource. Details: Gets a list of all PMA2020 indicators with publicly available data. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/indicators :name: example-of-collection-indicators { "metadata": { "..." }, "resultSize": 112, "results": [ { "definition": "Percent of women ages 15\u201349 who are using (or whose partners are using) any contraceptive method at the time of the survey", "denominator": "All women, ages 15-49", "domain": "Women's reproductive health", "favoriteOrder": 1, "id": "cp_all", "isFavorite": true, "label": "Current use of any contraceptive method (all women)", "level1": "Family planning utilization", "level2": "Contraceptive use", "measurementType": "percent", "order": 11, "type": "indicator", "url": "http://api.pma2020.org/v1/indicators/cp_all" }, "..." ] } """ indicators = Indicator.query.all() data = [i.full_json(endpoint='api.get_indicator') for i in indicators] return QuerySetApiResult(data, 'json')
def get_survey(code): """Survey resource entity GET method. .. :quickref: Survey rounds; Access a specific survey round by its code Args: code (str): Identification for resource entity. Query Args: None Returns: json: Entity of resource. Details: Access a specific PMA2020 country survey round with publicly available data, by its code. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/surveys/PMA2013_GHR1 :name: example-of-instance-survey { "metadata": { "..." }, "resultSize": 13, "results": { "country.id": "GH", "country.label": "Ghana", "country.order": 4, "country.region": "Africa", "country.subregion": "Western Africa", "end_date": "2013-10-01", "id": "PMA2013_GHR1", "order": 101, "pma_code": "GHR1", "round": 1, "start_date": "2013-09-01", "type": "PMA2020", "year": 2013 } } """ survey = Survey.query.filter_by(code=code).first() json_obj = survey.full_json() return QuerySetApiResult(json_obj, 'json')
def get_indicator(code): """Get Indicator resource entity. .. :quickref: Indicators; Access a specific indicator by its code Args: code (str): Identification for resource entity. Query Args: None Returns: json: Entity of resource. Details: Access a specific PMA2020 indicator with publicly available data, by its code. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/indicators/CODE :name: example-of-instance-indicator { "metadata": { "..." }, "resultSize": 12, "results": { "definition": "Percent of women ages 15\u201349 who are using (or whose partners are using) any contraceptive method at the time of the survey", "denominator": "All women, ages 15-49", "domain": "Women's reproductive health", "favoriteOrder": 1, "id": "cp_all", "isFavorite": true, "label": "Current use of any contraceptive method (all women)", "level1": "Family planning utilization", "level2": "Contraceptive use", "measurementType": "percent", "order": 11, "type": "indicator" } } """ indicator = Indicator.query.filter_by(code=code).first() json_obj = indicator.full_json() return QuerySetApiResult(json_obj, 'json')
def get_countries(): """Country resource collection GET method. .. :quickref: Countries; Get collection of countries. Args: Non-REST, Python API for function has no arguments. Query Args: None Returns: json: Collection for resource. Details: Gets a list of all PMA2020 countries with publicly available data. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/countries :name: example-of-collection-countries { "metadata": { "..." }, "resultSize": 10, "results": [ { "id": "BF", "label": "Burkina Faso", "order": 1, "region": "Africa", "subregion": "Western Africa" }, "..." ] } """ countries = Country.query.all() data = [c.full_json() for c in countries] return QuerySetApiResult(data, 'json')
def show_version(): """Show API version data. .. :quickref: Version; API versioning data. Args: n/a Returns: String: Version number. Details: Displays API's 2-part semantic version number. ALso displays versioning for datasets used. Example: .. code-block:: json :caption: GET /v1/version :name: example-of-endpoint-version { "datasetMetadata": [ { "createdOn": "Fri, 13 Jul 2018 20:25:42 GMT", "hash": "339ce036bdee399d449f95a1d4b3bb8f", "name": "api_data-2018.03.19-v29-SAS", "type": "api" }, { "createdOn": "Fri, 13 Jul 2018 20:25:43 GMT", "hash": "469542a93241da0af80269b6d7352600", "name": "ui_data-2017.10.02-v4-jef", "type": "ui" } ], "version": "0.1.9" } """ return jsonify(QuerySetApiResult.metadata())
def get_text(code): """Get Text resource entity. .. :quickref: Text; Access a specific piece of text by its code Args: code (str): Identification for resource entity. Query Args: None Returns: json: Entity of resource. Details: Access a specific piece of text related to surveys and metadata, by its code. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/texts/6EA0At85 :name: example-of-instance-text { "metadata": { "..." }, "resultSize": 3, "results": { "id": "6EA0At85", "langCode": "en", "text": "Kinshasa Province" } } """ text = EnglishString.query.filter_by(code=code).first() json_obj = text.to_json() return QuerySetApiResult(json_obj, 'json')
def get_resources(): """Return API resource routes. .. :quickref: Resources list; Lists all of the available API resources and their URLs. Args: Non-REST, Python API for function has no arguments. Query Args: None Returns: json: List of resources. Details: The resources object returned is split up into two main parts--results, and metadata. The metadata object contains information about the datasets used, including the client-specific "ui" dataset. The results object is the main object, which returns a list of resources, consisting of the resource name and its URL. The resource can then be accessed by using the literal URL string shown. Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/resources :name: example-of-collection-resources { "metadata": { "datasetMetadata": [ { "createdOn": "Fri, 13 Jul 2018 20:25:42 GMT", "hash": "339ce036bdee399d449f95a1d4b3bb8f", "name": "api_data-2018.03.19-v29-SAS", "type": "api" }, { "createdOn": "Fri, 13 Jul 2018 20:25:43 GMT", "hash": "469542a93241da0af80269b6d7352600", "name": "ui_data-2017.10.02-v4-jef", "type": "ui" } ], "version": "0.1.9" }, "resultSize": 1, "results": { "resources": [ { "name": "countries", "resource": "http://api.pma2020.org/v1/countries" }, { "name": "surveys", "resource": "http://api.pma2020.org/v1/surveys" }, { "name": "texts", "resource": "http://api.pma2020.org/v1/texts" }, { "name": "indicators", "resource": "http://api.pma2020.org/v1/indicators" }, { "name": "data", "resource": "http://api.pma2020.org/v1/data" }, { "name": "characteristicGroups", "resource": "http://api.pma2020.org/v1/characteristicGroups" } ] } } """ resource_endpoints = (('countries', 'api.get_countries'), ('surveys', 'api.get_surveys'), ('texts', 'api.get_texts'), ('indicators', 'api.get_indicators'), ('data', 'api.get_data'), ('characteristicGroups', 'api.get_characteristic_groups')) json_obj = { 'resources': [{ 'name': name, 'resource': url_for(route, _external=True) } for name, route in resource_endpoints] } return QuerySetApiResult(json_obj, 'json')
def get_texts(): """Get Text resource collection. .. :quickref: Text; Get collection of various text related to surveys and metadata. Args: Non-REST, Python API for function has no arguments. Query Args: None Returns: json: Collection for resource. Details: Get a list of various texts related to surveys and metadata. Default language displayed is English (en). Example: .. code-block:: json :caption: GET http://api.pma2020.org/v1/texts :name: example-of-collection-texts { "metadata": { "..." }, "resultSize": 515, "results": [ { "id": "6EA0At85", "langCode": "en", "text": "Kinshasa Province" }, { "id": "K9pC3w90", "langCode": "en", "text": "2013 Round 1" }, { "id": "0G2e7W61", "langCode": "en", "text": "Household / female questionnaire" }, { "id": "noFfI-js", "langCode": "en", "text": "Marital status" }, { "id": "qWyhZCgY", "langCode": "en", "text": "Married vs unmarried" }, "..." ] } """ english_strings = EnglishString.query.all() data = [d.to_json() for d in english_strings] return QuerySetApiResult(data, 'json')
def dynamic_route(resource: str) -> Union[QuerySetApiResult, str]: """Dynamically resource-based routing For any model resources that do not have explicit static routes created, this route will attempt to return a standardized list of results for that model. Args: resource(str): Resource requested in url of request Returns: QuerySetApiResult: Records queried for resource str: Standard 404 # TODO 1: Allow for public/non-public access settings. Psuedo code: # access_ok = hasattr(model, 'access') and model['access']['api'] \ # and model['access']['api']['public'] # public_attrs = [x for x in model['access']['api']['attributes'] # if x['public']] # # filter out key value pairs that are not public # # return json # TODO 5: Ideally I'd like to use a different approach, i.e. dynamically # generate and register a list of routes at server start. """ model = resource_model_map[resource] \ if resource in resource_model_map else None if model is None: # TODO 2: There's probably a better way to handle 404's in this case msg_404 = 'Error 404: Page not found' + '<br/>' resource_h1 = 'The resources available are limited to the following ' \ + '<ul>' resources: str = '<li>' + \ '</li><li>'.join(resource_model_map.keys()) + '</ul>' msg = '<br/>'.join([msg_404, resource_h1, resources]) return msg objects: List[Model] = model.query.all() if not request.args: dict_objs: [{}] = models_to_dicts(objects) QuerySetApiResult(record_list=dict_objs, return_format='json') query_dir = os.path.join(PROJECT_ROOT_PATH, 'pma_api') query_template_path = os.path.join(query_dir, 'python_query_template.py') query_tempfile_path = os.path.join(query_dir, 'python_query_tempfile.py') # TODO: review https://nedbatchelder.com/blog/201206/ # eval_really_is_dangerous.html arg_str = '' for k, v in request.args.items(): # TODO 3: Lots of other conversions. Consider as well using the literal # url string rather than request.args v = 'True' if v == 'true' else 'False' if v == 'false' else v arg_str += '_.{} == {}'.format(k, v) with open(query_template_path, 'r') as file: txt = file.read() # TODO 4: Use actual temp files with random names for concurrency with open(query_tempfile_path, 'w') as file: txt = txt.replace("'$'", arg_str) file.write(txt) # noinspection PyUnresolvedReferences from pma_api.python_query_tempfile import interpolated_query filtered_objs: List[Model] = interpolated_query(objects) os.remove(query_tempfile_path) dict_objs: [{}] = models_to_dicts(filtered_objs) response = QuerySetApiResult(record_list=dict_objs, return_format='json') return response