diff --git a/.all-contributorsrc b/.all-contributorsrc index de07f666..e0c81180 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -110,6 +110,15 @@ "contributions": [ "doc" ] + }, + { + "login": "carmelag", + "name": "carmelag", + "avatar_url": "https://avatars0.githubusercontent.com/u/5394906?v=4", + "profile": "http://www.carmelagreco.dev", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 4dce4c45..2c1b3304 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -

- coronavirus-tracker (API) -

- -> This is a fast (< 200ms) and basic API for tracking development of the new coronavirus (COVID-19, SARS-CoV-2). It's written in python using 🍼 Flask. Supports multiple sources! +## Coronavirus Tracker API +Provides up-to-date data about Coronavirus outbreak. Includes numbers about confirmed cases, deaths and recovered. +Support multiple data-sources. ![Travis build](https://api.travis-ci.com/ExpDev07/coronavirus-tracker-api.svg?branch=master) [![License](https://img.shields.io/github/license/ExpDev07/coronavirus-tracker-api)](LICENSE.md) @@ -20,26 +18,63 @@ ![Covid-19 Recovered](https://covid19-badges.herokuapp.com/recovered/latest) ![Covid-19 Deaths](https://covid19-badges.herokuapp.com/deaths/latest) -## Endpoints +## Available data-sources: + +Currently 2 different data-sources are available to retrieve the data: -All requests must be made to the base url: ``https://coronavirus-tracker-api.herokuapp.com/v2/`` (e.g: https://coronavirus-tracker-api.herokuapp.com/v2/locations). You can try them out in your browser to further inspect responses. +* **jhu** - https://github.com/CSSEGISandData/COVID-19 - Worldwide Data repository operated by the Johns Hopkins University Center for Systems Science and Engineering (JHU CSSE). -### Picking data source +* **csbs** - https://www.csbs.org/information-covid-19-coronavirus - U.S. County data that comes from the Conference of State Bank Supervisors. -We provide multiple data-sources you can pick from, simply add the query parameter ``?source=your_source_of_choice`` to your requests. JHU will be used as a default if you don't provide one. +__jhu__ data-source will be used as a default source if you don't specify a *source parameter* in your request. -#### Available sources: -* **jhu** - https://github.com/CSSEGISandData/COVID-19 - Data repository operated by the Johns Hopkins University Center for Systems Science and Engineering (JHU CSSE). +## API Reference -* **csbs** - https://www.csbs.org/information-covid-19-coronavirus - U.S. County data that comes from the Conference of State Bank Supervisors. +All endpoints are located at ``coronavirus-tracker-api.herokuapp.com/v2/`` and are accessible via https. For instance: you can get data per location by using this URL: +*[https://coronavirus-tracker-api.herokuapp.com/v2/locations](https://coronavirus-tracker-api.herokuapp.com/v2/locations)* + +You can open the URL in your browser to further inspect the response. Or you can make this curl call in your terminal to see the prettified response: + +``` +curl https://coronavirus-tracker-api.herokuapp.com/v2/locations | json_pp +``` + + +## API Endpoints + +### Sources Endpoint + +Getting the data-sources that are currently available to Coronavirus Tracker API to retrieve the data of the pandemic. + +```http +GET /v2/sources +``` + +__Sample response__ +```json +{ + "sources": [ + "jhu", + "csbs" + ] +} +``` -* **... more to come later**. +### Latest Endpoint + +Getting latest amount of total confirmed cases, deaths, and recovered. -### Getting latest amount of total confirmed cases, deaths, and recoveries. ```http GET /v2/latest ``` + +__Query String Parameters__ +| __Query string parameter__ | __Description__ | __Type__ | +| -------------------------- | -------------------------------------------------------------------------------- | -------- | +| source | The data-source where data will be retrieved from *(jhu/csbs)*. Default is *jhu* | String | + +__Sample response__ ```json { "latest": { @@ -50,10 +85,69 @@ GET /v2/latest } ``` -### Getting all locations. +### Locations Endpoint + +Getting latest amount of confirmed cases, deaths, and recovered per location. + +#### The Location Object +```http +GET /v2/locations/:id +``` + +__Path Parameters__ +| __Path parameter__ | __Required/Optional__ | __Description__ | __Type__ | +| ------------------ | --------------------- | ------------------------------------------------------------------------- | -------- | +| id | OPTIONAL | The unique location id for which you want to call the Locations Endpoint. | Integer | + +__Query String Parameters__ +| __Query string parameter__ | __Description__ | __Type__ | +| -------------------------- | -------------------------------------------------------------------------------- | -------- | +| source | The data-source where data will be retrieved from *(jhu/csbs)*. Default is *jhu* | String | + +#### Example Request +```http +GET /v2/locations/39 +``` + +__Sample response__ +```json +{ + "location": { + "id": 39, + "country": "Norway", + "country_code": "NO", + "province": "", + "last_updated": "2020-03-21T06:59:11.315422Z", + "coordinates": { }, + "latest": { }, + "timelines": { + "confirmed": { + "latest": 1463, + "timeline": { + "2020-03-16T00:00:00Z": 1333, + "2020-03-17T00:00:00Z": 1463 + } + }, + "deaths": { }, + "recovered": { } + } + } +} +``` + +#### List of all locations ```http GET /v2/locations ``` + +__Query String Parameters__ +| __Query string parameter__ | __Description__ | __Type__ | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | +| source | The data-source where data will be retrieved from.
__Value__ can be: *jhu/csbs*. __Default__ is *jhu* | String | +| country_code | The ISO ([alpha-2 country_code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)) to the Country/Province for which you're calling the Endpoint | String | +| timelines | To set the visibility of timelines (*daily tracking*).
__Value__ can be: *0/1*. __Default__ is *0* (timelines are not visible) | Integer | + +__Sample response__ ```json { "latest": { @@ -98,54 +192,76 @@ GET /v2/locations } ``` -Additionally, you can also filter by any attribute, including province and country ([alpha-2 country_code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)). -```http -GET /v2/locations?country_code=US -``` +__Response definitions__ +| __Response Item__ | __Description__ | __Type__ | +| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | +| {latest} | The total amount of confirmed cases, deaths and recovered for all the locations | Object | +| {latest}/confirmed | The up-to-date total number of confirmed cases for all the locations within the data-source | Integer | +| {latest}/deaths | The up-to-date total amount of deaths for all the locations within the data-source | Integer | +| {latest}/recovered | The up-to-date total amount of recovered for all the locations within the data-source | Integer | +| {locations} | The collection of locations contained within the data-source | Object | +| {location} | Information that identifies a location | Object | +| {latest} | The amount of confirmed cases, deaths and recovered related to the specific location | Object | +| {locations}/{location}/{latest}/confirmed | The up-to-date number of confirmed cases related to the specific location | Integer | +| {locations}/{location}/{latest}/deaths | The up-to-date number of deaths related to the specific location | Integer | +| {locations}/{location}/{latest}/recovered | The up-to-date number of recovered related to the specific location | Integer | +| {locations}/{location}/id | The location id. This unique id is assigned to the location by the data-source. | Integer | +| {locations}/{location}/country | The Country name | String | +| {locations}/{location}/country_code | The [ISO alpha-2 country_code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) Country code for the location. | String | +| {locations}/{location}/province | The province where the location belongs to. (Used for US locations coming from __csbs data-source__.
__Empty__ when *jhu data-source* is used | String | +| {locations}/{location}/{coordinates}/latitude | The location latitude | Float | +| {locations}/{location}/{coordinates}/longitude | The location longitude | Float | + + +### Example Requests with parameters + +__Parameter: country_code__ + +Getting data for the Country specified by the *country_code parameter*, in this case Italy - IT -Include timelines. ```http -GET /v2/locations?timelines=1 +GET /v2/locations?country_code=IT ``` -### Getting a specific location (includes timelines by default). -```http -GET /v2/locations/:id -``` +__Sample Response__ ```json { - "location": { - "id": 39, - "country": "Norway", - "country_code": "NO", - "province": "", - "last_updated": "2020-03-21T06:59:11.315422Z", - "coordinates": { }, - "latest": { }, - "timelines": { - "confirmed": { - "latest": 1463, - "timeline": { - "2020-03-16T00:00:00Z": 1333, - "2020-03-17T00:00:00Z": 1463 + "latest": { + "confirmed": 59138, + "deaths": 5476, + "recovered": 7024 + }, + "locations": [ + { + "coordinates": { + "latitude": "43", + "longitude": "12" + }, + "country": "Italy", + "country_code": "IT", + "id": 16, + "last_updated": "2020-03-23T13:32:23.913872Z", + "latest": { + "confirmed": 59138, + "deaths": 5476, + "recovered": 7024 + }, + "province": "" } - }, - "deaths": { }, - "recovered": { } - } - } + ] } ``` -Exclude timelines. -```http -GET /v2/locations?timelines=0 -``` +__Parameter: source__ + +Getting the data from the data-source specified by the *source parameter*, in this case [csbs](https://www.csbs.org/information-covid-19-coronavirus) + -### Getting US per county information. ```http GET /v2/locations?source=csbs ``` + +__Sample Response__ ```json { "latest": { @@ -194,6 +310,23 @@ GET /v2/locations?source=csbs } ``` +__Parameter: timelines__ + +Getting the data for all the locations including the daily tracking of confirmed cases, deaths and recovered per location. + +```http +GET /v2/locations?timelines=1 +``` +Explore the response by opening the URL in your browser [https://coronavirus-tracker-api.herokuapp.com/v2/locations?timelines=1](https://coronavirus-tracker-api.herokuapp.com/v2/locations?timelines=1) or make the following curl call in your terminal: + +``` +curl https://coronavirus-tracker-api.herokuapp.com/v2/locations?timelines=1 | json_pp +``` + +__NOTE:__ Timelines tracking starts from day 22nd January 2020 and ends to the last available day in the data-source. + + + ## Wrappers These are the available API wrappers created by the community. They are not necessarily maintained by any of this project's authors or contributors. @@ -284,6 +417,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Abdirahiim Yassin

📖
Darío Hereñú

📖
Oliver

📖 +
carmelag

📖 diff --git a/app/routes/__init__.py b/app/routes/__init__.py index b890a031..8d1f45eb 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint, redirect, request, current_app as app +from flask import Blueprint, redirect, request, abort, current_app as app from ..data import data_source # Follow the import order to avoid circular dependency @@ -6,7 +6,7 @@ api_v2 = Blueprint('api_v2', __name__, url_prefix='/v2') # API version 2. -from .v2 import locations, latest +from .v2 import locations, latest, sources # API version 1. from .v1 import confirmed, deaths, recovered, all @@ -23,8 +23,12 @@ def datasource(): Attaches the datasource to the request. """ # Retrieve the datas ource from query param. - source = request.args.get('source', type=str, default='jhu') + source = data_source(request.args.get('source', type=str, default='jhu')) + + # Abort with 404 if source cannot be found. + if not source: + return abort(404, description='The provided data-source was not found.') # Attach source to request and return it. - request.source = data_source(source) + request.source = source pass diff --git a/app/routes/v2/locations.py b/app/routes/v2/locations.py index f9104015..5a222b90 100644 --- a/app/routes/v2/locations.py +++ b/app/routes/v2/locations.py @@ -17,7 +17,7 @@ def locations(): try: locations = [j for j in locations if getattr(j, i) == args.get(i, type=str)] except AttributeError: - print('TimelinedLocation object does not have attribute {}.'.format(i)) + print('Location does not have attribute {}.'.format(i)) # Serialize each location and return. return jsonify({ diff --git a/app/routes/v2/sources.py b/app/routes/v2/sources.py new file mode 100644 index 00000000..749e3b70 --- /dev/null +++ b/app/routes/v2/sources.py @@ -0,0 +1,12 @@ +from flask import jsonify +from ...data import data_sources +from ...routes import api_v2 as api + +@api.route('/sources') +def sources(): + """ + Retrieves a list of data-sources that are availble to use. + """ + return jsonify({ + 'sources': list(data_sources.keys()) + }) diff --git a/app/services/location/csbs.py b/app/services/location/csbs.py index e63804af..f6140b75 100644 --- a/app/services/location/csbs.py +++ b/app/services/location/csbs.py @@ -38,28 +38,41 @@ def get_locations(): locations = [] for i, item in enumerate(data): + # General info. state = item['State Name'] county = item['County Name'] + + # Ensure country is specified. if county == "Unassigned" or county == "Unknown": continue - confirmed = int(item['Confirmed'] or 0) - death = int(item['Death'] or 0) - coordinates = Coordinates(float(item['Latitude']), float(item['Longitude'])) + # Coordinates. + coordinates = Coordinates( + item['Latitude'], + item['Longitude'] + ) + + # Date string without "EDT" at end. + last_update = ' '.join(item['Last Update'].split(' ')[0:2]) - # Parse time to ISO format - last_update = item['Last Update'] - date = last_update.split("-") - year = int(date[0]) - month = int(date[1]) - date = date[2].split(" ") - day = int(date[0]) - time = date[1].split(":") - hour = int(time[0]) - minute = int(time[1]) - d = datetime(year=year, month=month, day=day, hour=hour, minute=minute) - last_update = d.isoformat() + 'Z' + # Append to locations. + locations.append(CSBSLocation( + # General info. + i, state, county, + + # Coordinates. + Coordinates( + item['Latitude'], + item['Longitude'] + ), - locations.append(CSBSLocation(i, state, county, coordinates, last_update, confirmed, death)) + # Last update (parse as ISO). + datetime.strptime(last_update, '%Y/%m/%d %H:%M').isoformat() + 'Z', + + # Statistics. + int(item['Confirmed'] or 0), + int(item['Death'] or 0) + )) + # Return the locations. return locations diff --git a/tests/example_data/sample_covid19_county.csv b/tests/example_data/sample_covid19_county.csv index ee972c59..9f89341d 100644 --- a/tests/example_data/sample_covid19_county.csv +++ b/tests/example_data/sample_covid19_county.csv @@ -1,33 +1,33 @@ County Name,State Name,Confirmed,New,Death,Fatality Rate,Latitude,Longitude,Last Update -New York,New York,4408,454,26,0.6%,40.71455,-74.00714,2020-03-20 13:58 EDT -Westchester,New York,1091,293,0,0%,41.16319759,-73.7560629,2020-03-20 13:58 EDT -Nassau,New York,754,382,4,0.5%,40.74165225,-73.58899619,2020-03-20 13:58 EDT -Yakima,Washington,7,0,0,0%,46.60448,-120.50721,2020-03-20 13:58 EDT -Thurston,Washington,6,0,0,0%,46.91980578,-122.8298691,2020-03-20 13:58 EDT -Jefferson,Washington,4,0,0,0%,47.74810608,-123.6000095,2020-03-20 13:58 EDT -Douglas,Kansas,1,0,0,0%,38.88462907,-95.29255463,2020-03-20 13:58 EDT -Cherokee,Kansas,1,0,0,0%,37.16926692,-94.8462675759999,2020-03-20 13:58 EDT -Jackson,Kansas,1,0,0,0%,39.4168027220001,-95.793674403,2020-03-20 13:58 EDT -Twin Falls,Idaho,1,0,0,0%,42.55619,-114.4696,2020-03-20 13:58 EDT -Kootenai,Idaho,1,0,0,0%,47.6775872760001,-116.697131928,2020-03-20 13:58 EDT -Chittenden,Vermont,4,0,1,25%,44.45799511,-73.05404973,2020-03-20 13:58 EDT -Bennington,Vermont,3,0,0,0%,42.87672,-73.19818,2020-03-20 13:58 EDT -Windsor,Vermont,3,0,1,33.3%,43.48115,-72.38581,2020-03-20 13:58 EDT -Washington,Vermont,1,0,0,0%,44.27344561,-72.61485925,2020-03-20 13:58 EDT -Orange,Vermont,1,0,0,0%,44.14854,-72.40233,2020-03-20 13:58 EDT -Addison,Vermont,1,0,0,0%,44.0280736,-73.13152876,2020-03-20 13:58 EDT -Burleigh,North Dakota,11,0,0,0%,46.97801044,-100.4669442,2020-03-20 13:58 EDT -Tucker,West Virginia,2,0,0,0%,39.1135508250001,-79.56492129,2020-03-20 13:58 EDT -Mercer,West Virginia,1,0,0,0%,37.40556515,-81.11143231,2020-03-20 13:58 EDT -Monongalia,West Virginia,1,0,0,0%,39.630233859,-80.0465546289999,2020-03-20 13:58 EDT -Unassigned,New York,166,149,4,2.4%,42.165726,-74.948051,2020-03-20 13:58 EDT -Unassigned,Washington,151,0,0,0%,47.400902,-121.490494,2020-03-20 13:58 EDT -Unassigned,Colorado,57,0,0,0%,39.059811,-105.311104,2020-03-20 13:58 EDT -Unknown,Pennsylvania,55,55,0,0%,40.590752,-77.209755,2020-03-20 13:58 EDT -Unassigned,Pennsylvania,0,0,0,NaN%,40.590752,-77.209755,2020-03-20 13:58 EDT -Franklin,Pennsylvania,1,1,0,0%,39.927495836,-77.721161869,2020-03-20 13:58 EDT -Franklin,North Carolina,4,4,0,0%,36.0827448150001,-78.285600305,2020-03-20 13:58 EDT -Lee,North Carolina,1,1,0,0%,35.475059921,-79.17154054,2020-03-20 13:58 EDT -Clay,Minnesota,1,1,0,0%,46.892347886,-96.490737839,2020-03-20 13:58 EDT -Yuma,Arizona,1,1,0,0%,32.768956524,-113.905830295,2020-03-20 13:58 EDT -Dunklin,Missouri,1,1,0,0%,36.105848973,-90.16563,2020-03-20 13:58 EDT +New York,New York,4408,454,26,0.6%,40.71455,-74.00714,2020/03/20 13:58 EDT +Westchester,New York,1091,293,0,0%,41.16319759,-73.7560629,2020/03/20 13:58 EDT +Nassau,New York,754,382,4,0.5%,40.74165225,-73.58899619,2020/03/20 13:58 EDT +Yakima,Washington,7,0,0,0%,46.60448,-120.50721,2020/03/20 13:58 EDT +Thurston,Washington,6,0,0,0%,46.91980578,-122.8298691,2020/03/20 13:58 EDT +Jefferson,Washington,4,0,0,0%,47.74810608,-123.6000095,2020/03/20 13:58 EDT +Douglas,Kansas,1,0,0,0%,38.88462907,-95.29255463,2020/03/20 13:58 EDT +Cherokee,Kansas,1,0,0,0%,37.16926692,-94.8462675759999,2020/03/20 13:58 EDT +Jackson,Kansas,1,0,0,0%,39.4168027220001,-95.793674403,2020/03/20 13:58 EDT +Twin Falls,Idaho,1,0,0,0%,42.55619,-114.4696,2020/03/20 13:58 EDT +Kootenai,Idaho,1,0,0,0%,47.6775872760001,-116.697131928,2020/03/20 13:58 EDT +Chittenden,Vermont,4,0,1,25%,44.45799511,-73.05404973,2020/03/20 13:58 EDT +Bennington,Vermont,3,0,0,0%,42.87672,-73.19818,2020/03/20 13:58 EDT +Windsor,Vermont,3,0,1,33.3%,43.48115,-72.38581,2020/03/20 13:58 EDT +Washington,Vermont,1,0,0,0%,44.27344561,-72.61485925,2020/03/20 13:58 EDT +Orange,Vermont,1,0,0,0%,44.14854,-72.40233,2020/03/20 13:58 EDT +Addison,Vermont,1,0,0,0%,44.0280736,-73.13152876,2020/03/20 13:58 EDT +Burleigh,North Dakota,11,0,0,0%,46.97801044,-100.4669442,2020/03/20 13:58 EDT +Tucker,West Virginia,2,0,0,0%,39.1135508250001,-79.56492129,2020/03/20 13:58 EDT +Mercer,West Virginia,1,0,0,0%,37.40556515,-81.11143231,2020/03/20 13:58 EDT +Monongalia,West Virginia,1,0,0,0%,39.630233859,-80.0465546289999,2020/03/20 13:58 EDT +Unassigned,New York,166,149,4,2.4%,42.165726,-74.948051,2020/03/20 13:58 EDT +Unassigned,Washington,151,0,0,0%,47.400902,-121.490494,2020/03/20 13:58 EDT +Unassigned,Colorado,57,0,0,0%,39.059811,-105.311104,2020/03/20 13:58 EDT +Unknown,Pennsylvania,55,55,0,0%,40.590752,-77.209755,2020/03/20 13:58 EDT +Unassigned,Pennsylvania,0,0,0,NaN%,40.590752,-77.209755,2020/03/20 13:58 EDT +Franklin,Pennsylvania,1,1,0,0%,39.927495836,-77.721161869,2020/03/20 13:58 EDT +Franklin,North Carolina,4,4,0,0%,36.0827448150001,-78.285600305,2020/03/20 13:58 EDT +Lee,North Carolina,1,1,0,0%,35.475059921,-79.17154054,2020/03/20 13:58 EDT +Clay,Minnesota,1,1,0,0%,46.892347886,-96.490737839,2020/03/20 13:58 EDT +Yuma,Arizona,1,1,0,0%,32.768956524,-113.905830295,2020/03/20 13:58 EDT +Dunklin,Missouri,1,1,0,0%,36.105848973,-90.16563,2020/03/20 13:58 EDT