fetching data from external api with trpc

So i've watched a couple trpc videos, but I still don't know how to fetch data from some api for example: https://pokeapi.co/ with TRPC. TRPC is for sure the most confusing part of the stack for me. Am I just dumb?
PokéAPI
An open RESTful API for Pokémon data
9 Replies
Matvey
Matvey3y ago
You need tRPC on the server to use tRPC on the client. You can't fetch data from a REST API with tRPC Just use Fetch and React Query
Keef
Keef3y ago
Basically what ronan said but you can use trpc to interact with a rest api indirectly In your query/mutation you have to do the async work there which in this case would be doing the fetch*
Matvey
Matvey3y ago
You can also proxy the API with a tRPC server
julius
julius3y ago
You'd just put the fetch call in your procedure:
const pokeApiUrl = "https://pokeapi.co";

export const pokemonRouter = router({
getByName: publicProcedure
.input(z.object({ name: z.string() }))
.query(async ({ input }) => {
const pokeRes = await fetch(`${pokeApiUrl}/pokemon/${input.name}`);
// perhaps some error handling
if (!pokeRes.ok) {
throw new TRPCError(...);
}

// shold prob validate the shape with Zod
const validated = pokemonValidator.parse(pokeRes.json());
return validated;
}),
});

// then on the frontend just call it
const MyComp = () => {
const pokeQuery = trpc.pokemon.getByName({ name: "zapdos" });

return ...
};
const pokeApiUrl = "https://pokeapi.co";

export const pokemonRouter = router({
getByName: publicProcedure
.input(z.object({ name: z.string() }))
.query(async ({ input }) => {
const pokeRes = await fetch(`${pokeApiUrl}/pokemon/${input.name}`);
// perhaps some error handling
if (!pokeRes.ok) {
throw new TRPCError(...);
}

// shold prob validate the shape with Zod
const validated = pokemonValidator.parse(pokeRes.json());
return validated;
}),
});

// then on the frontend just call it
const MyComp = () => {
const pokeQuery = trpc.pokemon.getByName({ name: "zapdos" });

return ...
};
noctate
noctateOP3y ago
thx!!! now you advices make sense yours* So adding that, just to help me understand the idea: is fetching the data this way inside a trpc making it server side? Or do I have weird understanding of it? I'm sorry if this is dumb question I just want to understand it enough And how should I choose if I do or I don't need to use trpc in my example? For example if I want to display a filterable table of 100 pokemons which method of rendering I should choose?
julius
julius3y ago
this way your client fetches your server, then your server fetches the pokemon api you can just do the fetching on the client using react-query (or even swr) if this is the only fetching you'll do
const MyComp = () => {
const pokeQuery = useQuery(["getPokemon", async () => {
const pokeRes = await fetch(...);
...
}]);

return ...
};
const MyComp = () => {
const pokeQuery = useQuery(["getPokemon", async () => {
const pokeRes = await fetch(...);
...
}]);

return ...
};
but if you already have trpc setup its pretty neat to do the fetches from there i think and keeps it clean
noctate
noctateOP3y ago
Oh okay but if I plan to use trpc for other things some related with users, is it a good idea to keep all fetches in trpc? Oh i see Thx I guess Im starting to to get the idea also another question: what is this? const validated = pokemonValidator.parse
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
julius
julius3y ago
Yea you'd make a Zod validator that you can validate the data against. So lets say the API returns something like
{
data: [
{
id: "123",
name: "zapdos",
attackPower: 420,
idk: "whatever",
},
...
],
someOtherMetaData: {}
}
{
data: [
{
id: "123",
name: "zapdos",
attackPower: 420,
idk: "whatever",
},
...
],
someOtherMetaData: {}
}
you'd create your validator smth like this
const PokemonValidator = z.object({
id: z.string(),
name: z.string(),
attackPower: z.number(),
idk: z.string(),
});
type Pokemon = z.infer<typeof PokemonValidator>;

const responseValidator = z.array(PokemonValidator);
const PokemonValidator = z.object({
id: z.string(),
name: z.string(),
attackPower: z.number(),
idk: z.string(),
});
type Pokemon = z.infer<typeof PokemonValidator>;

const responseValidator = z.array(PokemonValidator);
and then you can validate the data something like this
const valid = responseValidator.safeParse(res.json().data);
if (!valid.success) {
console.error(valid.error);
}
// data is valid and typed
return valid.data;
const valid = responseValidator.safeParse(res.json().data);
if (!valid.success) {
console.error(valid.error);
}
// data is valid and typed
return valid.data;
So then if the API changes its response you'd get validation errors instead of runtime errors which makes it so much easier to debug

Did you find this page helpful?