Replies: 2 comments 1 reply
-
You're right that SWR doesn't have a built-in way to validate cached data against a schema at the cache level. However, you can implement this validation yourself using a custom fetcher or by wrapping your SWR hooks. Here's an approach you could take: Define your schemas (you could use a library like Zod, Yup, or JSON Schema for this) First, install Zod: npm install zod Then, create a utility function to wrap your SWR hooks: #validateSWR.ts
import { z } from 'zod';
import useSWR, { SWRResponse, SWRConfiguration } from 'swr';
export function useValidatedSWR<T>(
key: string,
fetcher: () => Promise<T>,
schema: z.ZodType<T>,
config?: SWRConfiguration
): SWRResponse<T, Error> {
return useSWR<T, Error>(
key,
async () => {
const data = await fetcher();
try {
return schema.parse(data);
} catch (error) {
console.error(`Data validation failed for key: ${key}`, error);
throw new Error('Data validation failed');
}
},
{
...config,
shouldRetryOnError: false,
}
);
} Now you can use this wrapper in your components: #UserProfile.tsx
import { z } from 'zod';
import { useValidatedSWR } from '../utils/validateSWR';
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof userSchema>;
function UserProfile({ userId }: { userId: number }) {
const { data, error } = useValidatedSWR<User>(
`/api/users/${userId}`,
() => fetch(`/api/users/${userId}`).then(res => res.json()),
userSchema
);
if (error) return <div>Failed to load user</div>;
if (!data) return <div>Loading...</div>;
return (
<div>
<h1>{data.name}</h1>
<p>{data.email}</p>
</div>
);
} |
Beta Was this translation helpful? Give feedback.
-
It's been a while since I learned “swr” so I don't know if this is the correct answer, but I think you can use “mutate” or “middleware” to get the behavior you want. For example
const schemaMiddleware = (useSWRNext) => (key, fetcher, config) => {
const swr = useSWRNext(key, fetcher, config);
if (swr.data) {
try {
swr.data = testSchema.parse(swr.data);
} catch (error) {
console.error(error);
}
}
return swr;
};
const { data } = useSWR("https://swapi.dev/api/people", fetcher, { use: [schemaMiddleware] }); This method technically validates cached data immediately after it is cached, rather than at any time, so it may not be what you're looking for
useEffect(() => {
const mutateData = async () => {
if (data) {
await mutate(
"https://swapi.dev/api/people",
() => {
try {
const parsedData = testSchema.parse(data);
return parsedData;
} catch (error) {
console.error(error);
return data;
}
},
{
revalidate: false,
}
);
}
};
mutateData();
}, [data]); It's not a well thought out example, and it's not clean code, but I think you might be able to get the behavior you want by applying it this way |
Beta Was this translation helpful? Give feedback.
-
I would like to make sure that the data in the cache (e.g. local storage) conforms to the schema I expect. The schema obviously varies per SWR key, so parsing can't be implemented at the cache level. From the docs, it doesn't seem like there's a way to parse the data when reading from the cache.
Beta Was this translation helpful? Give feedback.
All reactions