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
noctate3y 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
noctate3y 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
Want results from more Discord servers?
Add your server