diff --git a/README.md b/README.md deleted file mode 100644 index 7355d0af..00000000 --- a/README.md +++ /dev/null @@ -1,529 +0,0 @@ -

- 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) -[![Coverage Status](https://coveralls.io/repos/github/ExpDev07/coronavirus-tracker-api/badge.svg?branch=master)](https://coveralls.io/github/ExpDev07/coronavirus-tracker-api?branch=master) -[![License](https://img.shields.io/github/license/ExpDev07/coronavirus-tracker-api)](LICENSE.md) -[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) -[![GitHub stars](https://img.shields.io/github/stars/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/network/members) -[![GitHub last commit](https://img.shields.io/github/last-commit/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/commits/master) -[![GitHub pull requests](https://img.shields.io/github/issues-pr/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/pulls) -[![GitHub issues](https://img.shields.io/github/issues/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/issues) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/ExpDev07/coronavirus-tracker-api.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/ExpDev07/coronavirus-tracker-api/alerts/) -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -[![Tweet](https://img.shields.io/twitter/url?url=https%3A%2F%2Fgithub.com%2FExpDev07%2Fcoronavirus-tracker-api)](https://twitter.com/intent/tweet?text=COVID19%20Live%20Tracking%20API:%20&url=https%3A%2F%2Fgithub.com%2FExpDev07%2Fcoronavirus-tracker-api) - -**Live global stats (provided by [fight-covid19/bagdes](https://github.com/fight-covid19/bagdes)) from this API:** - -![Covid-19 Confirmed](https://covid19-badges.herokuapp.com/confirmed/latest) -![Covid-19 Recovered](https://covid19-badges.herokuapp.com/recovered/latest) -![Covid-19 Deaths](https://covid19-badges.herokuapp.com/deaths/latest) - -## New York Times is now available as a source! - -**Specify source parameter with ?source=nyt. NYT also provides a timeseries! To view timelines of cases by US counties use ?source=nyt&timelines=true** - -## Recovered cases showing 0 - -**JHU (our main data provider) [no longer provides data for amount of recoveries](https://github.com/CSSEGISandData/COVID-19/issues/1250), and as a result, the API will be showing 0 for this statistic. Apologies for any inconvenience. Hopefully we'll be able to find an alternative data-source that offers this.** - -## Available data-sources: - -Currently 3 different data-sources are available to retrieve the data: - -* **jhu** - https://github.com/CSSEGISandData/COVID-19 - Worldwide Data repository operated by the Johns Hopkins University Center for Systems Science and Engineering (JHU CSSE). - -* **csbs** - https://www.csbs.org/information-covid-19-coronavirus - U.S. County data that comes from the Conference of State Bank Supervisors. - -* **nyt** - https://github.com/nytimes/covid-19-data - The New York Times is releasing a series of data files with cumulative counts of coronavirus cases in the United States. This API provides the timeseries at the US county level. - -__jhu__ data-source will be used as a default source if you don't specify a *source parameter* in your request. - -## API Reference - -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 -``` - -### Swagger/OpenAPI - -Consume our API through [our super awesome and interactive SwaggerUI](https://coronavirus-tracker-api.herokuapp.com/) (on mobile, use the [mobile friendly ReDocs](https://coronavirus-tracker-api.herokuapp.com/docs) instead for the best experience). - - -The [OpenAPI](https://swagger.io/docs/specification/about/) json definition can be downloaded at https://coronavirus-tracker-api.herokuapp.com/openapi.json - -## 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", - "nyt" - ] -} -``` - -### Latest Endpoint - -Getting latest amount of total confirmed cases, deaths, and recovered. - -```http -GET /v2/latest -``` - -__Query String Parameters__ -| __Query string parameter__ | __Description__ | __Type__ | -| -------------------------- | -------------------------------------------------------------------------------- | -------- | -| source | The data-source where data will be retrieved from *(jhu/csbs/nyt)*. Default is *jhu* | String | - -__Sample response__ -```json -{ - "latest": { - "confirmed": 197146, - "deaths": 7905, - "recovered": 80840 - } -} -``` - -### 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. The list of valid location IDs (:id) can be found in the locations response: ``/v2/locations`` | Integer | - -__Query String Parameters__ -| __Query string parameter__ | __Description__ | __Type__ | -| -------------------------- | -------------------------------------------------------------------------------- | -------- | -| source | The data-source where data will be retrieved from *(jhu/csbs/nyt)*. Default is *jhu* | String | - -#### Example Request -```http -GET /v2/locations/39 -``` - -__Sample response__ -```json -{ - "location": { - "id": 39, - "country": "Norway", - "country_code": "NO", - "country_population": 5009150, - "province": "", - "county": "", - "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/nyt*. __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": { - "confirmed": 272166, - "deaths": 11299, - "recovered": 87256 - }, - "locations": [ - { - "id": 0, - "country": "Thailand", - "country_code": "TH", - "country_population": 67089500, - "province": "", - "county": "", - "last_updated": "2020-03-21T06:59:11.315422Z", - "coordinates": { - "latitude": "15", - "longitude": "101" - }, - "latest": { - "confirmed": 177, - "deaths": 1, - "recovered": 41 - } - }, - { - "id": 39, - "country": "Norway", - "country_code": "NO", - "province": "", - "county": "", - "last_updated": "2020-03-21T06:59:11.315422Z", - "coordinates": { - "latitude": "60.472", - "longitude": "8.4689" - }, - "latest": { - "confirmed": 1463, - "deaths": 3, - "recovered": 1 - } - } - ] -} -``` - -__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 - -```http -GET /v2/locations?country_code=IT -``` - -__Sample Response__ -```json -{ - "latest": { - "confirmed": 59138, - "deaths": 5476, - "recovered": 7024 - }, - "locations": [ - { - "id": 16, - "country": "Italy", - "country_code": "IT", - "country_population": 60340328, - "province": "", - "county": "", - "last_updated": "2020-03-23T13:32:23.913872Z", - "coordinates": { - "latitude": "43", - "longitude": "12" - }, - "latest": { - "confirmed": 59138, - "deaths": 5476, - "recovered": 7024 - } - } - ] -} -``` - -__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) - - -```http -GET /v2/locations?source=csbs -``` - -__Sample Response__ -```json -{ - "latest": { - "confirmed": 7596, - "deaths": 43, - "recovered": 0 - }, - "locations": [ - { - "id": 0, - "country": "US", - "country_code": "US", - "country_population": 310232863, - "province": "New York", - "state": "New York", - "county": "New York", - "last_updated": "2020-03-21T14:00:00Z", - "coordinates": { - "latitude": 40.71455, - "longitude": -74.00714 - }, - "latest": { - "confirmed": 6211, - "deaths": 43, - "recovered": 0 - } - }, - { - "id": 1, - "country": "US", - "country_code": "US", - "country_population": 310232863, - "province": "New York", - "state": "New York", - "county": "Westchester", - "last_updated": "2020-03-21T14:00:00Z", - "coordinates": { - "latitude": 41.16319759, - "longitude": -73.7560629 - }, - "latest": { - "confirmed": 1385, - "deaths": 0, - "recovered": 0 - }, - } - ] -} -``` - -__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. - -### PHP - -* [CovidPHP by @o-ba](https://github.com/o-ba/covid-php). - -### Golang - -* [Go-corona by @itsksaurabh](https://github.com/itsksaurabh/go-corona). - -### C# - -* [CovidSharp by @Abdirahiim](https://github.com/Abdirahiim/covidtrackerapiwrapper) -* [Covid19Tracker.NET by @egbakou](https://github.com/egbakou/Covid19Tracker.NET) -* [CovidDotNet by @degant](https://github.com/degant/CovidDotNet) - -### Python - -* [COVID19Py by @Kamaropoulos](https://github.com/Kamaropoulos/COVID19Py). - -### Java - -* [Coronavirus by @mew](https://github.com/mew/Coronavirus). - -### Node.js - -* [jhucsse.covid by @Sem1084](https://www.npmjs.com/package/jhucsse.covid). - -### Ruby - -* [covid19-data-ruby by @jaerodyne](https://github.com/jaerodyne/covid19-data-ruby). - -### Lua - -* [lua-covid-data by @imolein](https://codeberg.org/imo/lua-covid-data). - -## Prerequisites - -You will need the following things properly installed on your computer. - -* [Python 3](https://www.python.org/downloads/) (with pip) -* [pipenv](https://pypi.org/project/pipenv/) - -## Installation - -* `git clone https://github.com/ExpDev07/coronavirus-tracker-api.git` -* `cd coronavirus-tracker-api` - -1. Make sure you have [`python3.8` installed and on your `PATH`](https://docs.python-guide.org/starting/installation/). -2. [Install the `pipenv` dependency manager](https://pipenv.readthedocs.io/en/latest/install/#installing-pipenv) - * with [pipx](https://pipxproject.github.io/pipx/) `$ pipx install pipenv` - * with [Homebrew/Linuxbrew](https://pipenv.readthedocs.io/en/latest/install/#homebrew-installation-of-pipenv) `$ brew install pipenv` - * with [pip/pip3 directly](https://pipenv.readthedocs.io/en/latest/install/#pragmatic-installation-of-pipenv) `$ pip install --user pipenv` -3. Create virtual environment and install all dependencies `$ pipenv sync --dev` -4. Activate/enter the virtual environment `$ pipenv shell` - -And don't despair if don't get the python setup working on the first try. No one did. Guido got pretty close... once. But that's another story. Good luck. - -## Running / Development - -For a live reloading on code changes. - -* `pipenv run dev` - -Without live reloading. - -* `pipenv run start` - -Visit your app at [http://localhost:8000](http://localhost:8000). - -Alternatively run our API with Docker. - -### Running Tests -> [pytest](https://docs.pytest.org/en/latest/) - -```bash -pipenv run test -``` - - -### Linting -> [pylint](https://www.pylint.org/) - -```bash -pipenv run lint -``` - -### Formatting -> [black](https://black.readthedocs.io/en/stable/) - -```bash -pipenv run fmt -``` - -### Update requirements files - -```bash -invoke generate-reqs -``` - -[Pipfile.lock](./Pipfile.lock) will be automatically updated during `pipenv install`. - -### Docker - -Our Docker image is based on [tiangolo/uvicorn-gunicorn-fastapi/](https://hub.docker.com/r/tiangolo/uvicorn-gunicorn-fastapi/). - -```bash -invoke docker --build -``` - -Run with `docker run` or `docker-compose` - -#### Alternate Docker images - -If a full `gunicorn` deployment is unnecessary or [impractical on your hardware](https://fastapi.tiangolo.com/deployment/#raspberry-pi-and-other-architectures) consider using our single instance [`Uvicorn`](https://www.uvicorn.org/) based [Dockerfile](uvicorn.Dockerfile). - - -### Invoke - -Additional developer commands can be run by calling them with the [python `invoke` task runner](http://www.pyinvoke.org/). -```bash -invoke --list -``` - -### Deploying - -## Contributors ✨ - -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ExpDev

πŸ’» πŸ“– 🚧

bjarkimg

πŸ’¬

Bost

πŸ“–

GRIBOK

πŸ’» ⚠️

Oliver Thamm

πŸ“–

Mauro M.

πŸ“–

JKSenthil

πŸ’» πŸ“– ⚠️

SeanCena

πŸ’» πŸ“– ⚠️

Abdirahiim Yassin

πŸ“– πŸ”§ πŸ“¦

DarΓ­o HereΓ±ΓΊ

πŸ“–

Oliver

πŸ“–

carmelag

πŸ“–

Gabriel

πŸ’» πŸš‡ ⚠️ πŸ“–

Kodjo Laurent Egbakou

πŸ“– πŸ”§ πŸ“¦

Turreted

πŸ’»

Ibtida Bhuiyan

πŸ’» πŸ“–

James Gray

πŸ’»

Nischal Shankar

πŸ’» πŸ“–
- - - - - -## License - -See [LICENSE.md](LICENSE.md) for the license. Please link to this repo somewhere in your project :). diff --git a/app/data/__init__.py b/app/data/__init__.py deleted file mode 100644 index 265bf3d3..00000000 --- a/app/data/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -"""app.data""" -from ..services.location.csbs import CSBSLocationService -from ..services.location.jhu import JhuLocationService -from ..services.location.nyt import NYTLocationService - -# Mapping of services to data-sources. -DATA_SOURCES = {"jhu": JhuLocationService(), "csbs": CSBSLocationService(), "nyt": NYTLocationService()} - - -def data_source(source): - """ - Retrieves the provided data-source service. - - :returns: The service. - :rtype: LocationService - """ - return DATA_SOURCES.get(source.lower()) diff --git a/app/services/location/nyt.py b/app/services/location/nyt.py deleted file mode 100644 index a6435166..00000000 --- a/app/services/location/nyt.py +++ /dev/null @@ -1,130 +0,0 @@ -"""app.services.location.nyt.py""" -import csv -import logging -from datetime import datetime - -from asyncache import cached -from cachetools import TTLCache - -from ...coordinates import Coordinates -from ...location.nyt import NYTLocation -from ...timeline import Timeline -from ...utils import httputils -from . import LocationService - -LOGGER = logging.getLogger("services.location.nyt") - - -class NYTLocationService(LocationService): - """ - Service for retrieving locations from New York Times (https://github.com/nytimes/covid-19-data). - """ - - async def get_all(self): - # Get the locations. - locations = await get_locations() - return locations - - async def get(self, loc_id): # pylint: disable=arguments-differ - # Get location at the index equal to provided id. - locations = await self.get_all() - return locations[loc_id] - - -# --------------------------------------------------------------- - - -# Base URL for fetching category. -BASE_URL = "https://raw.githubusercontent.com/nytimes/covid-19-data/master/us-counties.csv" - - -def get_grouped_locations_dict(data): - """ - Helper function to group history for locations into one dict. - - :returns: The complete data for each unique US county - :rdata: dict - """ - grouped_locations = {} - - # in increasing order of dates - for row in data: - county_state = (row["county"], row["state"]) - date = row["date"] - confirmed = row["cases"] - deaths = row["deaths"] - - # initialize if not existing - if county_state not in grouped_locations: - grouped_locations[county_state] = {"confirmed": [], "deaths": []} - - # append confirmed tuple to county_state (date, # confirmed) - grouped_locations[county_state]["confirmed"].append((date, confirmed)) - # append deaths tuple to county_state (date, # deaths) - grouped_locations[county_state]["deaths"].append((date, deaths)) - - return grouped_locations - - -@cached(cache=TTLCache(maxsize=1024, ttl=3600)) -async def get_locations(): - """ - Returns a list containing parsed NYT data by US county. The data is cached for 1 hour. - - :returns: The complete data for US Counties. - :rtype: dict - """ - # Request the data. - LOGGER.info("nyt Requesting data...") - async with httputils.CLIENT_SESSION.get(BASE_URL) as response: - text = await response.text() - - LOGGER.info("Data received") - - # Parse the CSV. - data = list(csv.DictReader(text.splitlines())) - LOGGER.info("nyt CSV parsed") - - # Group together locations (NYT data ordered by dates not location). - grouped_locations = get_grouped_locations_dict(data) - - # The normalized locations. - locations = [] - - for idx, (county_state, histories) in enumerate(grouped_locations.items()): - # Make location history for confirmed and deaths from dates. - # List is tuples of (date, amount) in order of increasing dates. - confirmed_list = histories["confirmed"] - confirmed_history = {date: int(amount or 0) for date, amount in confirmed_list} - - deaths_list = histories["deaths"] - deaths_history = {date: int(amount or 0) for date, amount in deaths_list} - - # Normalize the item and append to locations. - locations.append( - NYTLocation( - id=idx, - state=county_state[1], - county=county_state[0], - coordinates=Coordinates(None, None), # NYT does not provide coordinates - last_updated=datetime.utcnow().isoformat() + "Z", # since last request - timelines={ - "confirmed": Timeline( - { - datetime.strptime(date, "%Y-%m-%d").isoformat() + "Z": amount - for date, amount in confirmed_history.items() - } - ), - "deaths": Timeline( - { - datetime.strptime(date, "%Y-%m-%d").isoformat() + "Z": amount - for date, amount in deaths_history.items() - } - ), - "recovered": Timeline({}), - }, - ) - ) - LOGGER.info("nyt Data normalized") - - return locations