-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathsplitApi.ts
More file actions
148 lines (131 loc) · 6.74 KB
/
splitApi.ts
File metadata and controls
148 lines (131 loc) · 6.74 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { IPlatform } from '../sdkFactory/types';
import { ISettings } from '../types';
import { splitHttpClientFactory } from './splitHttpClient';
import { ISplitApi } from './types';
import { objectAssign } from '../utils/lang/objectAssign';
import { ITelemetryTracker } from '../trackers/types';
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MEMBERSHIPS } from '../utils/constants';
import { ERROR_TOO_MANY_SETS } from '../logger/constants';
const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
function userKeyToQueryParam(userKey: string) {
return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
}
/**
* Factory of SplitApi objects, which group the collection of Split HTTP endpoints used by the SDK
*
* @param settings - validated settings object
* @param platform - object containing environment-specific dependencies
* @param telemetryTracker - telemetry tracker
*/
export function splitApiFactory(
settings: ISettings,
platform: Pick<IPlatform, 'getOptions' | 'getFetch'>,
telemetryTracker: ITelemetryTracker
): ISplitApi {
const urls = settings.urls;
const filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
const SplitSDKImpressionsMode = settings.sync.impressionsMode;
const splitHttpClient = splitHttpClientFactory(settings, platform);
return {
// @TODO throw errors if health check requests fail, to log them in the Synchronizer
getSdkAPIHealthCheck() {
const url = `${urls.sdk}/version`;
return splitHttpClient(url).then(() => true).catch(() => false);
},
getEventsAPIHealthCheck() {
const url = `${urls.events}/version`;
return splitHttpClient(url).then(() => true).catch(() => false);
},
fetchAuth(userMatchingKeys?: string[]) {
let url = `${urls.auth}/v2/auth?s=${settings.sync.flagSpecVersion}`;
if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
const queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
if (queryParams) url += '&' + queryParams;
}
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN));
},
fetchSplitChanges(since: number, noCache?: boolean, till?: number, rbSince?: number) {
const url = `${urls.sdk}/splitChanges?s=${settings.sync.flagSpecVersion}&since=${since}${rbSince ? '&rbSince=' + rbSince : ''}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
.catch((err) => {
if (err.statusCode === 414) settings.log.error(ERROR_TOO_MANY_SETS);
throw err;
});
},
fetchSegmentChanges(since: number, segmentName: string, noCache?: boolean, till?: number) {
const url = `${urls.sdk}/segmentChanges/${segmentName}?since=${since}${till ? '&till=' + till : ''}`;
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
},
fetchMemberships(userMatchingKey: string, noCache?: boolean, till?: number) {
/**
* URI encoding of user keys in order to:
* - avoid 400 responses (due to URI malformed). E.g.: '/api/memberships/%'
* - avoid 404 responses. E.g.: '/api/memberships/foo/bar'
* - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
*/
const url = `${urls.sdk}/memberships/${encodeURIComponent(userMatchingKey)}${till ? '?till=' + till : ''}`;
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MEMBERSHIPS));
},
/**
* Post events.
*
* @param body - Events bulk payload
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
*/
postEventsBulk(body: string, headers?: Record<string, string>) {
const url = `${urls.events}/events/bulk`;
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(EVENTS));
},
/**
* Post impressions.
*
* @param body - Impressions bulk payload
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
*/
postTestImpressionsBulk(body: string, headers?: Record<string, string>) {
const url = `${urls.events}/testImpressions/bulk`;
return splitHttpClient(url, {
// Adding extra headers to send impressions in OPTIMIZED or DEBUG modes.
method: 'POST', body, headers: objectAssign({ SplitSDKImpressionsMode }, headers)
}, telemetryTracker.trackHttp(IMPRESSIONS));
},
/**
* Post impressions counts.
*
* @param body - Impressions counts payload
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
*/
postTestImpressionsCount(body: string, headers?: Record<string, string>) {
const url = `${urls.events}/testImpressions/count`;
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(IMPRESSIONS_COUNT));
},
/**
* Post unique keys for client side.
*
* @param body - unique keys payload
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
*/
postUniqueKeysBulkCs(body: string, headers?: Record<string, string>) {
const url = `${urls.telemetry}/v1/keys/cs`;
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY));
},
/**
* Post unique keys for server side.
*
* @param body - unique keys payload
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
*/
postUniqueKeysBulkSs(body: string, headers?: Record<string, string>) {
const url = `${urls.telemetry}/v1/keys/ss`;
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY));
},
postMetricsConfig(body: string, headers?: Record<string, string>) {
const url = `${urls.telemetry}/v1/metrics/config`;
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY), true);
},
postMetricsUsage(body: string, headers?: Record<string, string>) {
const url = `${urls.telemetry}/v1/metrics/usage`;
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY), true);
}
};
}