Skip to content

Commit 1b47afa

Browse files
committed
fix(apiOptions): strip undefined values from options in queryKey
1 parent 6cb7ee0 commit 1b47afa

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

static/app/utils/api/apiOptions.spec.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,21 @@ describe('apiOptions', () => {
5454
]);
5555
});
5656

57+
it('should strip undefined values from options in queryKey', () => {
58+
const options = apiOptions.as<unknown>()('/api-tokens/$tokenId/', {
59+
staleTime: 0,
60+
path: {tokenId: '123'},
61+
query: {cursor: 'abc'},
62+
method: undefined,
63+
});
64+
65+
expect(options.queryKey).toEqual([
66+
{infinite: false, version: 'v2'},
67+
'/api-tokens/123/',
68+
{query: {cursor: 'abc'}},
69+
]);
70+
});
71+
5772
it('should stringify number path params', () => {
5873
const options = apiOptions.as<unknown>()('/api-tokens/$tokenId/', {
5974
staleTime: 0,

static/app/utils/api/apiOptions.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ type PathParamOptions<TApiPath extends string> =
2323
? {path?: never}
2424
: {path: Record<ExtractPathParams<TApiPath>, string | number> | SkipToken};
2525

26-
function hasDefinedValues(obj: Record<string, unknown>): boolean {
27-
return Object.values(obj).some(v => v !== undefined);
26+
function stripUndefinedValues(obj: Record<string, unknown>): Record<string, unknown> {
27+
return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
2828
}
2929

3030
const selectJson = <TData>(data: ApiResponse<TData>) => data.json;
@@ -47,11 +47,13 @@ function _apiOptions<
4747
: [Options & PathParamOptions<TApiPath>]
4848
) {
4949
const url = getApiUrl(path, ...([{path: pathParams}] as OptionalPathParams<TApiPath>));
50+
const strippedOptions = stripUndefinedValues(options);
5051

5152
return queryOptions({
52-
queryKey: hasDefinedValues(options)
53-
? ([{infinite: false, version: 'v2'}, url, options] as ApiQueryKey)
54-
: ([{infinite: false, version: 'v2'}, url] as ApiQueryKey),
53+
queryKey:
54+
Object.keys(strippedOptions).length > 0
55+
? ([{infinite: false, version: 'v2'}, url, strippedOptions] as ApiQueryKey)
56+
: ([{infinite: false, version: 'v2'}, url] as ApiQueryKey),
5557
queryFn: pathParams === skipToken ? skipToken : apiFetch<TActualData>,
5658
enabled: pathParams !== skipToken,
5759
staleTime,
@@ -80,11 +82,13 @@ function _apiOptionsInfinite<
8082
: [Options & PathParamOptions<TApiPath>]
8183
) {
8284
const url = getApiUrl(path, ...([{path: pathParams}] as OptionalPathParams<TApiPath>));
85+
const strippedOptions = stripUndefinedValues(options);
8386

8487
return infiniteQueryOptions({
85-
queryKey: hasDefinedValues(options)
86-
? ([{infinite: true, version: 'v2'}, url, options] as InfiniteApiQueryKey)
87-
: ([{infinite: true, version: 'v2'}, url] as InfiniteApiQueryKey),
88+
queryKey:
89+
Object.keys(strippedOptions).length > 0
90+
? ([{infinite: true, version: 'v2'}, url, strippedOptions] as InfiniteApiQueryKey)
91+
: ([{infinite: true, version: 'v2'}, url] as InfiniteApiQueryKey),
8892
queryFn: pathParams === skipToken ? skipToken : apiFetchInfinite<TActualData>,
8993
getPreviousPageParam: parsePageParam('previous'),
9094
getNextPageParam: parsePageParam('next'),

0 commit comments

Comments
 (0)