Setting up the fetcher
The next piece of the puzzle is to create a fetcher function that the application will use to request data from the server. You can find more details about it in the imports article.
The fetcher is going to implement a transformResponse function that processes all incoming data by passing it to the registry’s parse method.
In the simplest form, when we expect JSON responses only, the function looks like this:
import { createFetcher } from "vovk";
import { useRegistry } from "@/registry";
export const fetcher = createFetcher({
transformResponse: (data) => {
const state = useRegistry.getState();
state.parse(data);
return data;
},
});On each RPC method call, the transformResponse function is invoked with the response data, which is then passed to the registry’s parse method.
import { UserRPC } from "vovk-client";
const users = await UserRPC.getUsers(); // transformResponse is called internallyThis also works with React Query, where useQuery doesn’t require to read the data property anymore:
import { useQuery } from "@tanstack/react-query";
import { UserRPC } from "vovk-client";
// ...
useQuery({
queryKey: UserRPC.getUsers.queryKey(),
queryFn: () => UserRPC.getUsers(),
})
// ...
const users = useRegistry(
useShallow((state) => userIds.map((id) => state.user[id])),
);Because our app also supports JSONLines responses for streaming data, we’re going to enhance the function a bit with another if check.
It’s also useful to have an option to bypass the registry for specific requests, so we’re going to add a bypassRegistry option to the fetcher config. It’s declared as a createFetcher generic parameter and used as an option in the second argument of transformResponse. It can be used as follows: await UserRPC.getUsers({ bypassRegistry: true }). You can extend this options object over time if needed.
import { createFetcher, HttpStatus } from "vovk";
import useRegistry from "@/hooks/useRegistry";
export const fetcher = createFetcher<{ bypassRegistry?: boolean }>({
transformResponse: async (data, { bypassRegistry }) => {
if (bypassRegistry) {
return data;
}
const state = useRegistry.getState();
if (
data &&
typeof data === "object" &&
Symbol.asyncIterator in data &&
"onIterate" in data &&
typeof data.onIterate === "function"
) {
data.onIterate(state.parse); // handle each item in the async iterable
return data;
}
state.parse(data); // parse regular JSON data
return data;
},
onError: (error) => {
if (error.statusCode === HttpStatus.UNAUTHORIZED) {
document.location.href = "/login";
}
},
});The code above is fetched from GitHub repository.
Declare the fetcher in the config. It replaces the default fetcher imported by the generated client.
// @ts-check
/** @type {import('vovk').VovkConfig} */
const config = {
outputConfig: {
imports: {
// ...
fetcher: './src/lib/fetcher.ts',
},
},
};
export default config;That’s it. From now on, each request is processed by the registry’s parse method, and manual response handling is not required.