UNPKG

@publichealthengland/uk-covid19

Version:

This is a JavaScript SDK for the COVID-19 API, as published by Public Health England on Coronavirus (COVID-19) in the UK dashboard.

251 lines (213 loc) 6.85 kB
/** * Coronavirus (COVID-19) Dashboard - API Service * ============================================== * * Software Development Kit (SDK) for JavaScript * --------------------------------------------- * * This is a Python SDK for the COVID-19 API, as published by * Public Health England on `Coronavirus (COVID-19) in the UK`_ * dashboard. * * The endpoint for the data provided using this SDK is: * * https://api.coronavirus.data.gov.uk/v1/data * * .. _`Coronavirus (COVID-19) in the UK`: http://coronavirus.data.gov.uk/ */ import axios from 'axios'; import moment from 'moment'; export type FiltersType = string[]; export interface StructureType { [key: string]: string; } export interface HeadType { [key: string]: string; } export interface OptionsType { [key: string]: any; } export interface UKCovid19Props { filters: FiltersType; structure: StructureType; latestBy?: string; } export interface APIParams { filters: string; structure: string; latestBy?: string; } export interface APIJSONResponse { data: StructureType[]; } export interface JSONResponse { data: StructureType[]; length: number; lastUpdate: string; totalPages: number; } /** * COVID-19 API * ------------ * Interface to access the API service for COVID-19 data in the United Kingdom. */ class Cov19API { static readonly endpoint: string = 'https://api.coronavirus.data.gov.uk/v1/data'; private readonly structure: StructureType; private readonly filters: string[]; private readonly latestBy: string | undefined; private _lastUpdate: string | undefined; /** * * @param filters { FiltersType } API filters. See the API documentations for * additional information. * * @param structure { StructureType } Structure parameter. See the API * documentations for additional information. * * @param latestBy { latestBy } Retrieves the latest value for a specific * metric. [Default: ``undefined``] * * @see https://coronavirus.data.gov.uk//developers-guide */ constructor({ filters, structure, latestBy }: UKCovid19Props) { this.filters = filters; this.structure = structure; this.latestBy = latestBy; } // constructor /** * API parameters, constructed based on ``filters``, ``structure``, * and ``latest_by`` arguments as defined by the user. * * @returns { APIParams } */ get apiParams(): APIParams { return { filters: this.filters.join(';'), structure: JSON.stringify(this.structure), ...(this.latestBy ? { latestBy: this.latestBy } : {}), }; } // apiParams /** * Extracts paginated data by requesting all of the pages * and combining the results. * * @param format { string } * * @returns { Promise<APIJSONResponse[] | string[]> } */ private getData = async ( format: string, ): Promise<APIJSONResponse[] | string[]> => { const result = []; let currentPage = 1; while (true) { const { data, status, statusText, headers } = await axios.get( Cov19API.endpoint, { params: { ...this.apiParams, page: currentPage, format }, timeout: 10000, }, ); if (status === 204) break; if (status >= 400) throw new Error(statusText); this._lastUpdate = headers['last-modified']; result.push(data); currentPage++; } return result; }; // getData /** * Provides full data (all pages) in JSON. * * @returns { Promise<JSONResponse> } */ getJSON = async (): Promise<JSONResponse> => { const data = (await this.getData('json')) as APIJSONResponse[]; const responseData = data.reduce( (acc, item) => [...acc, ...(item?.data ?? [])], [] as StructureType[], ); return { data: responseData, length: responseData.length, totalPages: data.length, lastUpdate: await this.lastUpdate(), }; }; // getJSON /** * Request header for the given input arguments (``filters``, * ``structure``, and ``lastest_by``). * * @returns { Promise<HeadType> } */ head = async (): Promise<HeadType> => { const { headers, status, statusText } = await axios.head( Cov19API.endpoint, { params: this.apiParams, timeout: 10000, responseType: 'text', method: 'HEAD', }, ); if (status >= 400) throw new Error(statusText); return headers; }; // head /** * Produces the timestamp for the last update in GMT. * * @returns { Promise<string> } */ lastUpdate = async (): Promise<string> => { const head = await this.head(); const lastModified = head['last-modified']; if (this._lastUpdate && this._lastUpdate.indexOf('Z') > -1) return this._lastUpdate; // Original format: Mon, 03 Aug 2020 14:46:40 GMT this._lastUpdate = moment( lastModified.replace(/\s+GMT$/i, ' Z'), 'ddd, DD MMM YYYY HH:mm:ss Z', ).toISOString(); return this._lastUpdate; }; // lastUpdate /** * Provides the options by calling the ``OPTIONS`` method of the API. * * @returns { Promise<OptionsType> } */ static options = async (): Promise<OptionsType> => { const { data, status, statusText, } = await axios.options(Cov19API.endpoint, { timeout: 10000 }); if (status >= 400) throw new Error(statusText); return data; }; // options /** * Provides full data (all pages) in CSV. * * .. warning:: * Please make sure that the ``structure`` is not hierarchical as * CSV outputs are defined as 2D tables and as such, do not support * hierarchies. * * @returns { Promise<string> } */ getCSV = async (): Promise<string> => { const data = (await this.getData('csv')) as string[]; return ( data.reduce( (acc: string, item: string, index: number) => acc + (index === 0 ? item.trim() : item.trim().split('\n').slice(1).join('\n')), '', ) + '\n' ); }; // getCSV } // Cov19API export default Cov19API;