Skip to content

Commit a4928eb

Browse files
fix: remove request which is handled by fetchAndHandleErrors (#2613)
fix: rename `requestWithOrgId` to `request`
1 parent 1575168 commit a4928eb

File tree

7 files changed

+48
-170
lines changed

7 files changed

+48
-170
lines changed

public/app/services/apps.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ describe('appsService', () => {
647647
])(
648648
`server returned='%s', should transform into %s`,
649649
async (response, expected) => {
650-
const spy = jest.spyOn(base, 'requestWithOrgID');
650+
const spy = jest.spyOn(base, 'request');
651651
spy.mockReturnValue(Promise.resolve(Result.ok(response)));
652652

653653
const res = await fetchApps();
@@ -658,7 +658,7 @@ describe('appsService', () => {
658658
});
659659

660660
it('works', async () => {
661-
const spy = jest.spyOn(base, 'requestWithOrgID');
661+
const spy = jest.spyOn(base, 'request');
662662
spy.mockReturnValue(Promise.resolve(Result.ok(mockData)));
663663

664664
const res = await fetchApps();
@@ -750,7 +750,7 @@ describe('appsService', () => {
750750
});
751751

752752
it('works with pyroscope_app or service_name', async () => {
753-
const spy = jest.spyOn(base, 'requestWithOrgID');
753+
const spy = jest.spyOn(base, 'request');
754754
const mockData = {
755755
labelsSet: [
756756
{
@@ -821,7 +821,7 @@ describe('appsService', () => {
821821
// The server will return with that level of granularity
822822
// Which is not required to build an "App"
823823
it('remove duplicates from same _profile_type__/name pair', async () => {
824-
const spy = jest.spyOn(base, 'requestWithOrgID');
824+
const spy = jest.spyOn(base, 'request');
825825
const mockData = {
826826
labelsSet: [
827827
{
@@ -889,7 +889,7 @@ describe('appsService', () => {
889889
});
890890

891891
it('filters out flagSets without pyroscope_app nor service_name', async () => {
892-
const spy = jest.spyOn(base, 'requestWithOrgID');
892+
const spy = jest.spyOn(base, 'request');
893893
const mockData = {
894894
labelsSet: [
895895
{

public/app/services/apps.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ import {
88
import { Result } from '@pyroscope/util/fp';
99
import { z, ZodError } from 'zod';
1010
import type { RequestError } from '@pyroscope/services/base';
11-
import {
12-
parseResponse,
13-
request,
14-
requestWithOrgID,
15-
} from '@pyroscope/services/base';
11+
import { parseResponse, request } from '@pyroscope/services/base';
1612

1713
// SeriesResponse refers to the response from the server, without any manipulation
1814
const SeriesResponseSchema = z.preprocess(
@@ -86,7 +82,7 @@ export async function fetchApps(
8682
fromMs?: number,
8783
untilMs?: number
8884
): Promise<Result<App[], RequestError | ZodError>> {
89-
let response = await requestWithOrgID('/querier.v1.QuerierService/Series', {
85+
let response = await request('/querier.v1.QuerierService/Series', {
9086
method: 'POST',
9187
body: JSON.stringify({
9288
matchers: [],
@@ -110,7 +106,7 @@ export async function fetchApps(
110106
}
111107

112108
// try without labelNames in case of an error since this has been added in a later version
113-
response = await requestWithOrgID('/querier.v1.QuerierService/Series', {
109+
response = await request('/querier.v1.QuerierService/Series', {
114110
method: 'POST',
115111
body: JSON.stringify({
116112
matchers: [],

public/app/services/base.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { requestWithOrgID } from '@pyroscope/services/base';
1+
import { request } from '@pyroscope/services/base';
22
import * as storageSvc from '@pyroscope/services/storage';
33

44
jest.mock('@pyroscope/services/base', () => {
@@ -36,7 +36,7 @@ describe('base', () => {
3636
});
3737

3838
it('uses X-Scope-OrgID if set manually', () => {
39-
requestWithOrgID('/', {
39+
request('/', {
4040
headers: {
4141
'X-Scope-OrgID': 'myID',
4242
},
@@ -54,7 +54,7 @@ describe('base', () => {
5454

5555
tenantIdSpy.mockReturnValueOnce('');
5656

57-
requestWithOrgID('/');
57+
request('/');
5858

5959
expect(global.fetch).toHaveBeenCalledWith('http://localhost/', {
6060
headers: {},
@@ -66,7 +66,7 @@ describe('base', () => {
6666

6767
tenantIdSpy.mockReturnValueOnce('myid');
6868

69-
requestWithOrgID('/');
69+
request('/');
7070

7171
expect(global.fetch).toHaveBeenCalledWith('http://localhost/', {
7272
headers: {

public/app/services/base.ts

Lines changed: 5 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class RequestNotOkError extends CustomError {
2020
* request wraps around the original request
2121
* while sending the OrgID if available
2222
*/
23-
export async function requestWithOrgID(
23+
export async function request(
2424
request: RequestInfo,
2525
config?: RequestInit
2626
): Promise<Result<unknown, RequestError>> {
@@ -62,7 +62,7 @@ export async function downloadWithOrgID(
6262
});
6363
}
6464

65-
export async function connectDownload(
65+
async function connectDownload(
6666
request: RequestInfo,
6767
config?: RequestInit
6868
): Promise<Result<Response, RequestError>> {
@@ -73,7 +73,7 @@ export async function connectDownload(
7373
return Result.ok(await response.value);
7474
}
7575

76-
export async function connectRequest(
76+
async function connectRequest(
7777
request: RequestInfo,
7878
config?: RequestInit
7979
): Promise<Result<unknown, RequestError>> {
@@ -247,7 +247,7 @@ function join(base: string, path: string): string {
247247
return `${base}/${path}`;
248248
}
249249

250-
export function mountURL(req: RequestInfo): string {
250+
function mountURL(req: RequestInfo): string {
251251
const baseName = basename();
252252

253253
if (baseName) {
@@ -266,7 +266,7 @@ export function mountURL(req: RequestInfo): string {
266266
return new URL(`${req}`, window.location.href).href;
267267
}
268268

269-
export function mountRequest(req: RequestInfo): RequestInfo {
269+
function mountRequest(req: RequestInfo): RequestInfo {
270270
const url = mountURL(req);
271271

272272
if (typeof req === 'string') {
@@ -279,114 +279,6 @@ export function mountRequest(req: RequestInfo): RequestInfo {
279279
};
280280
}
281281

282-
export async function request(
283-
request: RequestInfo,
284-
config?: RequestInit
285-
): Promise<Result<unknown, RequestError>> {
286-
const req = mountRequest(request);
287-
let response: Response;
288-
try {
289-
response = await fetch(req, config);
290-
} catch (e) {
291-
// 'e' is unknown, but most cases it should be an Error
292-
let message = '';
293-
if (e instanceof Error) {
294-
message = e.message;
295-
}
296-
297-
if (e instanceof Error && e.name === 'AbortError') {
298-
return Result.err(new RequestAbortedError(message));
299-
}
300-
301-
return Result.err(new RequestIncompleteError(message));
302-
}
303-
304-
if (!response.ok) {
305-
const textBody = await response.text();
306-
307-
// There's nothing in the body, so let's use a default message
308-
if (!textBody || !textBody.length) {
309-
return Result.err(
310-
new RequestNotOkError(response.status, 'No description available')
311-
);
312-
}
313-
314-
// We know there's data, so let's check if it's in JSON format
315-
try {
316-
const data = JSON.parse(textBody);
317-
318-
// Check if it's 401 unauthorized error
319-
if (response.status === 401) {
320-
// TODO: Introduce some kind of interceptor (?)
321-
// if (!/\/(login|signup)$/.test(window?.location?.pathname)) {
322-
// window.location.href = mountURL('/login');
323-
// }
324-
return Result.err(new RequestNotOkError(response.status, data.error));
325-
}
326-
327-
// Usually it's a feedback on user's actions like form validation
328-
if ('errors' in data && Array.isArray(data.errors)) {
329-
return Result.err(
330-
new RequestNotOkWithErrorsList(response.status, data.errors)
331-
);
332-
}
333-
334-
// Error message may come in an 'error' field
335-
if ('error' in data && typeof data.error === 'string') {
336-
return Result.err(new RequestNotOkError(response.status, data.error));
337-
}
338-
339-
// Error message may come in an 'message' field
340-
if ('message' in data && typeof data.message === 'string') {
341-
return Result.err(new RequestNotOkError(response.status, data.message));
342-
}
343-
344-
return Result.err(
345-
new RequestNotOkError(
346-
response.status,
347-
`Could not identify an error message. Payload is ${JSON.stringify(
348-
data
349-
)}`
350-
)
351-
);
352-
} catch (e) {
353-
// We couldn't parse, but there's definitly some data
354-
// We must handle this case since the go server sometimes responds with plain text
355-
356-
// It's HTML
357-
// Which normally happens when hitting a broken URL, which makes the server return the SPA
358-
// Poor heuristic for identifying it's a html file
359-
if (/<\/?[a-z][\s\S]*>/i.test(textBody)) {
360-
return Result.err(
361-
new ResponseNotOkInHTMLFormat(response.status, textBody)
362-
);
363-
}
364-
return Result.err(new RequestNotOkError(response.status, textBody));
365-
}
366-
}
367-
368-
// Server responded with 2xx
369-
const textBody = await response.text();
370-
371-
// There's nothing in the body
372-
if (!textBody || !textBody.length) {
373-
return Result.ok({
374-
statusCode: response.status,
375-
});
376-
}
377-
378-
// We know there's data, so let's check if it's in JSON format
379-
try {
380-
const data = JSON.parse(textBody);
381-
382-
// We could parse the response
383-
return Result.ok(data);
384-
} catch (e) {
385-
// We couldn't parse, but there's definitly some data
386-
return Result.err(new ResponseOkNotInJSONFormat(response.status, textBody));
387-
}
388-
}
389-
390282
// We have to call it something else otherwise it will conflict with the global "Response"
391283
type ResponseFromRequest = Awaited<ReturnType<typeof request>>;
392284
type Schema = Parameters<typeof modelToResult>[0];

public/app/services/render.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ import {
1414
import { Timeline, TimelineSchema } from '@pyroscope/models/timeline';
1515
import { Annotation, AnnotationSchema } from '@pyroscope/models/annotation';
1616
import type { RequestError } from '@pyroscope/services/base';
17-
import {
18-
request,
19-
parseResponse,
20-
requestWithOrgID,
21-
} from '@pyroscope/services/base';
17+
import { request, parseResponse } from '@pyroscope/services/base';
2218

2319
export interface RenderOutput {
2420
profile: Profile;
@@ -50,7 +46,7 @@ export async function renderSingle(
5046
): Promise<Result<RenderOutput, RequestError | ZodError>> {
5147
const url = buildRenderURL(props);
5248
// TODO
53-
const response = await requestWithOrgID(`/pyroscope${url}&format=json`, {
49+
const response = await request(`/pyroscope${url}&format=json`, {
5450
signal: controller?.signal,
5551
});
5652

@@ -110,7 +106,7 @@ export async function renderDiff(
110106
rightUntil: props.rightUntil,
111107
});
112108

113-
const response = await requestWithOrgID(`/pyroscope/render-diff?${params}`, {
109+
const response = await request(`/pyroscope/render-diff?${params}`, {
114110
signal: controller?.signal,
115111
});
116112

@@ -156,7 +152,7 @@ export async function renderExplore(
156152
}
157153
): Promise<Result<RenderExploreOutput, RequestError | ZodError>> {
158154
const url = buildRenderURL(props);
159-
const response = await requestWithOrgID(`/pyroscope/${url}&format=json`, {
155+
const response = await request(`/pyroscope/${url}&format=json`, {
160156
signal: controller?.signal,
161157
});
162158
return parseResponse<RenderExploreOutput>(response, RenderExploreSchema);

public/app/services/tags.ts

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { parseResponse, requestWithOrgID } from '@pyroscope/services/base';
1+
import { parseResponse, request } from '@pyroscope/services/base';
22
import { z } from 'zod';
33

44
const labelNamesSchema = z.preprocess(
@@ -33,20 +33,17 @@ export function queryToMatchers(query: string) {
3333
}
3434

3535
export async function fetchTags(query: string, from: number, until: number) {
36-
const response = await requestWithOrgID(
37-
'/querier.v1.QuerierService/LabelNames',
38-
{
39-
method: 'POST',
40-
body: JSON.stringify({
41-
matchers: queryToMatchers(query),
42-
start: from,
43-
end: until,
44-
}),
45-
headers: {
46-
'content-type': 'application/json',
47-
},
48-
}
49-
);
36+
const response = await request('/querier.v1.QuerierService/LabelNames', {
37+
method: 'POST',
38+
body: JSON.stringify({
39+
matchers: queryToMatchers(query),
40+
start: from,
41+
end: until,
42+
}),
43+
headers: {
44+
'content-type': 'application/json',
45+
},
46+
});
5047
const isMetaTag = (tag: string) => tag.startsWith('__') && tag.endsWith('__');
5148

5249
return parseResponse<string[]>(
@@ -63,21 +60,18 @@ export async function fetchLabelValues(
6360
from: number,
6461
until: number
6562
) {
66-
const response = await requestWithOrgID(
67-
'/querier.v1.QuerierService/LabelValues',
68-
{
69-
method: 'POST',
70-
body: JSON.stringify({
71-
matchers: queryToMatchers(query),
72-
name: label,
73-
start: from,
74-
end: until,
75-
}),
76-
headers: {
77-
'content-type': 'application/json',
78-
},
79-
}
80-
);
63+
const response = await request('/querier.v1.QuerierService/LabelValues', {
64+
method: 'POST',
65+
body: JSON.stringify({
66+
matchers: queryToMatchers(query),
67+
name: label,
68+
start: from,
69+
end: until,
70+
}),
71+
headers: {
72+
'content-type': 'application/json',
73+
},
74+
});
8175

8276
return parseResponse<string[]>(
8377
response,

public/app/services/tenant.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { RequestNotOkError, requestWithOrgID } from '@pyroscope/services/base';
1+
import { RequestNotOkError, request } from '@pyroscope/services/base';
22

33
export async function isMultiTenancyEnabled() {
4-
const res = await requestWithOrgID('/querier.v1.QuerierService/LabelNames', {
4+
const res = await request('/querier.v1.QuerierService/LabelNames', {
55
// Without this it would automatically add the OrgID
66
// Which doesn't tell us whether multitenancy is enabled or not
77
headers: {
@@ -22,7 +22,7 @@ export async function isMultiTenancyEnabled() {
2222
return isOrgRequiredError(res);
2323
}
2424

25-
function isOrgRequiredError(res: Awaited<ReturnType<typeof requestWithOrgID>>) {
25+
function isOrgRequiredError(res: Awaited<ReturnType<typeof request>>) {
2626
// TODO: is 'no org id' a stable message?
2727
return (
2828
res.isErr &&

0 commit comments

Comments
 (0)