-
Notifications
You must be signed in to change notification settings - Fork 0
/
openuv.ts
117 lines (102 loc) · 4.29 KB
/
openuv.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import {
DailyProtectionTimeParams, DailyProtectionTimeResponse, ForecastResponse, OpenUVParams, RealTimeUVResponse
} from "./types";
/**
* Get real-time UV Index by location. Optional altitude, ozone level and datetime could be provided as query parameters.
* @param apiKey API key from [OpenUV.io](https://www.openuv.io)
*/
export async function getRealTimeUV(apiKey: string, options?: OpenUVParams): Promise<RealTimeUVResponse> {
return standardOpenUVRequest("https://api.openuv.io/api/v1/uv", apiKey, options);
}
/**
* Get hourly UV Index Forecast by location and date. Optional altitude, ozone level and datetime could be provided.
* @param apiKey Your API key from [OpenUV.io](https://www.openuv.io)
*/
export function getForecast(apiKey: string, options?: OpenUVParams): Promise<ForecastResponse> {
return standardOpenUVRequest("https://api.openuv.io/api/v1/forecast", apiKey, options);
}
/**
* Get protection time by location, UV "from" and UV "to" values with 10 minutes accuracy. Optional altitude and ozone level could be provided.
* @param apiKey Your API key from [OpenUV.io](https://www.openuv.io)
*/
export async function getDailyProtectionTime(
apiKey: string,
options?: DailyProtectionTimeParams
): Promise<DailyProtectionTimeResponse> {
const regularOptions = await getOptions(options);
const cleanOptions = { from: options?.from, to: options?.to, ...regularOptions } as DailyProtectionTimeParams;
const url = createUrlWithParams("https://api.openuv.io/api/v1/protection", cleanOptions);
const response = await fetch(url, {
method: "GET",
headers: new Headers({
"x-access-token": apiKey,
}),
});
return handleJSONResponse(response);
}
/**
* Client that will passthrough to function with original API Key. Just to avoid passing around the API key.
* If you're going to use a single function, I would just recommend using the functions.
*/
export class OpenUVClient {
constructor(private apiKey: string) {}
/** {@inheritDoc getRealTimeUV} */
getRealTimeUV(options?: OpenUVParams) {
return getRealTimeUV(this.apiKey, options);
}
/** {@inheritDoc getForecast} */
getForecast(options?: OpenUVParams) {
return getForecast(this.apiKey, options);
}
/** {@inheritDoc getDailyProtectionTime} */
getDailyProtectionTime(options?: DailyProtectionTimeParams) {
return getDailyProtectionTime(this.apiKey, options);
}
}
async function standardOpenUVRequest<T>(endpoint: string, apiKey: string, options?: OpenUVParams): Promise<T> {
const cleanOptions = await getOptions(options);
const url = createUrlWithParams(endpoint, cleanOptions);
const response = await fetch(url, {
method: "GET",
headers: new Headers({
"x-access-token": apiKey,
}),
});
return handleJSONResponse(response);
}
async function getOptions(options?: OpenUVParams): Promise<OpenUVParams> {
let { lat, lng, alt, ozone, dt } = options ?? {};
// If lat or lng not provided, attempt to use Geolocation API
if (!lat || !lng) {
if (!navigator?.geolocation?.getCurrentPosition) {
throw new Error("Geolocation API is not availible, provide lat and lng in parameters");
}
let {
coords: { latitude, longitude, altitude },
} = await new Promise<GeolocationPosition>((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
lat = latitude;
lng = longitude;
alt = altitude ?? undefined;
}
if (lat && lng) {
return { lat, lng, alt, ozone, dt };
}
throw new Error("lat or lng not set");
}
function createUrlWithParams(endpoint: string, options: { [key: string]: unknown }): string {
const url = new URL(endpoint);
for (const key in options) {
if (options[key]) {
url.searchParams.set(key, String(options[key]));
}
}
return url.toString();
}
async function handleJSONResponse<T>(response: Response): Promise<T> {
if (response.ok) {
return await response.json();
}
throw new Error(`${response.status} ${response.statusText} - ${(await response.json()).error}`);
}