Visitar URL original
feat(api): Read the API base path from the spec's server URL by sentry-junior[bot] · Pull Request #20787 · getsentry/sentry-docs · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/build/open-api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export type DeRefedOpenAPI = {
};
};
tags: Tag[];
servers?: ServerMeta[];
};

export type ResponseContent = {
Expand Down
22 changes: 21 additions & 1 deletion src/build/resolveOpenAPI.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {describe, expect, test} from 'vitest';

import {toDocumentedParameter} from './resolveOpenAPI';
import {apiLocation, toDocumentedParameter} from './resolveOpenAPI';

const EXPERIMENTAL_NOTICE =
'**Experimental:** This parameter is under active development and may change.\n\n';
Expand Down Expand Up @@ -44,3 +44,23 @@ describe('toDocumentedParameter', () => {
);
});
});

describe('apiLocation', () => {
const regional = [{url: 'https://{region}.sentry.io/api/0'}];

test.each([
[
'paths carry the base path',
[{url: 'https://{region}.sentry.io'}],
undefined,
'/api/0/organizations/',
],
['the server URL carries it', regional, undefined, '/organizations/'],
['an operation server carries it', regional, regional, '/organizations/'],
])('shows the full path when %s', (_, specServers, operationServers, path) => {
expect(apiLocation(path, specServers, operationServers)).toEqual({
apiPath: '/api/0/organizations/',
server: operationServers ? 'https://{region}.sentry.io' : 'https://sentry.io',
});
});
});
27 changes: 21 additions & 6 deletions src/build/resolveOpenAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,25 @@ export function toDocumentedParameter<T extends ExperimentalExtension>(
};
}

const DEFAULT_SERVER = 'https://sentry.io';
const SERVER_URL = /^([a-z][a-z0-9+.-]*:\/\/[^/]*)(\/.*)?$/i;

// Sentry's spec puts the API base path, such as `/api/0`, in its server URL, and its
// paths are relative to it. Pages show the origin and the full path after it.
export function apiLocation(
path: string,
specServers: {url: string}[] | undefined,
operationServers: {url: string}[] | undefined
): {apiPath: string; server: string} {
const operationServer = operationServers?.[0]?.url;
const [, origin = DEFAULT_SERVER, basePath = ''] =
SERVER_URL.exec(operationServer ?? specServers?.[0]?.url ?? '') ?? [];
return {
apiPath: `${basePath.replace(/\/+$/, '')}${path}`,
server: operationServer ? origin : DEFAULT_SERVER,
};
}

function isDeprecatedOperationId(operationId: string | undefined): boolean {
return operationId ? DEPRECATED_PREFIX_REGEX.test(operationId) : false;
}
Expand Down Expand Up @@ -168,18 +187,14 @@ async function apiCategoriesUncached(): Promise<APICategory[]> {
const titleSource = apiData.summary || apiData.operationId || '';
const cleanName = stripDeprecatedPrefix(titleSource);

let server = 'https://sentry.io';
if (apiData.servers && apiData.servers[0]) {
server = apiData.servers[0].url;
}
const location = apiLocation(apiPath, data.servers, apiData.servers);
apiData.tags.forEach(tag => {
categoryMap[tag].apis.push({
apiPath,
...location,
method,
name: cleanName,
deprecated: isDeprecated,
experimental: isExperimental,
server,
slug: slugify(cleanName),
summary: apiData.summary
? stripDeprecatedPrefix(apiData.summary)
Expand Down
Loading