Skip to content

Commit 621792f

Browse files
HugeLettersEvgenii Perminov
and
Evgenii Perminov
authored
Fix invalid data check in query/mutation fn (#1975)
* check specifically for undefined in data for throwing errors * add changeset * add biome as default formatter for typescript react * improve data checks in query/mutation fns * add tests * test fix * add hugeletters to contributs list of react-query package * dont throw in mutations on undefined * fix changeset * fix mutation tests --------- Co-authored-by: Evgenii Perminov <[email protected]>
1 parent d29e53f commit 621792f

File tree

5 files changed

+105
-5
lines changed

5 files changed

+105
-5
lines changed

.changeset/spotty-flies-knock.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"openapi-react-query": patch
3+
---
4+
5+
- Fixed empty value check in queryFn: only throws error for undefined, other falsy values are allowed
6+
- Fixed empty value check in mutationFn: allow falsy values

.vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"[markdown]": {
99
"editor.defaultFormatter": "esbenp.prettier-vscode"
1010
},
11-
"[typescript]": {
11+
"[typescript][typescriptreact]": {
1212
"editor.defaultFormatter": "biomejs.biome"
1313
}
1414
}

docs/scripts/update-contributors.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ const CONTRIBUTORS = {
182182
"armandabric",
183183
"illright",
184184
]),
185-
"openapi-react-query": new Set(["drwpow", "kerwanp", "yoshi2no"]),
185+
"openapi-react-query": new Set(["drwpow", "kerwanp", "yoshi2no", "HugeLetters"]),
186186
"swr-openapi": new Set(["htunnicliff"]),
187187
"openapi-metadata": new Set(["kerwanp", "drwpow"]),
188188
};

packages/openapi-react-query/src/index.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,10 @@ export default function createClient<Paths extends {}, Media extends MediaType =
115115
const mth = method.toUpperCase() as Uppercase<typeof method>;
116116
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
117117
const { data, error } = await fn(path, { signal, ...(init as any) }); // TODO: find a way to avoid as any
118-
if (error || !data) {
118+
if (error) {
119119
throw error;
120120
}
121+
121122
return data;
122123
};
123124

@@ -141,10 +142,11 @@ export default function createClient<Paths extends {}, Media extends MediaType =
141142
const mth = method.toUpperCase() as Uppercase<typeof method>;
142143
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
143144
const { data, error } = await fn(path, init as InitWithUnknowns<typeof init>);
144-
if (error || !data) {
145+
if (error) {
145146
throw error;
146147
}
147-
return data;
148+
149+
return data as Exclude<typeof data, undefined>;
148150
},
149151
...options,
150152
},

packages/openapi-react-query/test/index.test.tsx

+92
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,50 @@ describe("client", () => {
283283
expect(data).toBeUndefined();
284284
});
285285

286+
it("should resolve data properly and have error as null when queryFn returns null", async () => {
287+
const fetchClient = createFetchClient<paths>({ baseUrl });
288+
const client = createClient(fetchClient);
289+
290+
useMockRequestHandler({
291+
baseUrl,
292+
method: "get",
293+
path: "/string-array",
294+
status: 200,
295+
body: null,
296+
});
297+
298+
const { result } = renderHook(() => client.useQuery("get", "/string-array"), { wrapper });
299+
300+
await waitFor(() => expect(result.current.isFetching).toBe(false));
301+
302+
const { data, error } = result.current;
303+
304+
expect(data).toBeNull();
305+
expect(error).toBeNull();
306+
});
307+
308+
it("should resolve error properly and have undefined data when queryFn returns undefined", async () => {
309+
const fetchClient = createFetchClient<paths>({ baseUrl });
310+
const client = createClient(fetchClient);
311+
312+
useMockRequestHandler({
313+
baseUrl,
314+
method: "get",
315+
path: "/string-array",
316+
status: 200,
317+
body: undefined,
318+
});
319+
320+
const { result } = renderHook(() => client.useQuery("get", "/string-array"), { wrapper });
321+
322+
await waitFor(() => expect(result.current.isFetching).toBe(false));
323+
324+
const { data, error } = result.current;
325+
326+
expect(error).toBeInstanceOf(Error);
327+
expect(data).toBeUndefined();
328+
});
329+
286330
it("should infer correct data and error type", async () => {
287331
const fetchClient = createFetchClient<paths>({ baseUrl, fetch: fetchInfinite });
288332
const client = createClient(fetchClient);
@@ -560,6 +604,54 @@ describe("client", () => {
560604
expect(error?.message).toBe("Something went wrong");
561605
});
562606

607+
it("should resolve data properly and have error as null when mutationFn returns null", async () => {
608+
const fetchClient = createFetchClient<paths>({ baseUrl });
609+
const client = createClient(fetchClient);
610+
611+
useMockRequestHandler({
612+
baseUrl,
613+
method: "put",
614+
path: "/comment",
615+
status: 200,
616+
body: null,
617+
});
618+
619+
const { result } = renderHook(() => client.useMutation("put", "/comment"), { wrapper });
620+
621+
result.current.mutate({ body: { message: "Hello", replied_at: 0 } });
622+
623+
await waitFor(() => expect(result.current.isPending).toBe(false));
624+
625+
const { data, error } = result.current;
626+
627+
expect(data).toBeNull();
628+
expect(error).toBeNull();
629+
});
630+
631+
it("should resolve data properly and have error as null when mutationFn returns undefined", async () => {
632+
const fetchClient = createFetchClient<paths>({ baseUrl });
633+
const client = createClient(fetchClient);
634+
635+
useMockRequestHandler({
636+
baseUrl,
637+
method: "put",
638+
path: "/comment",
639+
status: 200,
640+
body: undefined,
641+
});
642+
643+
const { result } = renderHook(() => client.useMutation("put", "/comment"), { wrapper });
644+
645+
result.current.mutate({ body: { message: "Hello", replied_at: 0 } });
646+
647+
await waitFor(() => expect(result.current.isPending).toBe(false));
648+
649+
const { data, error } = result.current;
650+
651+
expect(error).toBeNull();
652+
expect(data).toBeUndefined();
653+
});
654+
563655
it("should use provided custom queryClient", async () => {
564656
const fetchClient = createFetchClient<paths>({ baseUrl });
565657
const client = createClient(fetchClient);

0 commit comments

Comments
 (0)