recommended pattern to work with
hi, i love this library but there is one catch with it and is when adding a new service/endpoint requests, it feels kinda a slow process (at least the way im doing it) which is the following
add a new directory in the api folder with the endpoint name
make an index.ts file with the querykeys for that service
make a get.ts, post.ts, patch.ts, delete.ts for the main requests (this is mainly because i need to have different types for the responses, even if sometimes is the same entity, because some of them have different fields yada yada
putting the queries in a context provider file so i can have access to them
but all of these feel numbing and dumb and too complex for the sake of it, but i cant really come up with something that is quite right, i think i can omit the step of using the context but idk hjadsfjhdsaj i think i might ended up making a whole mess for nothing
if someone wanna share a project like a midsize or whatever i would be really really grateful
5 Replies
foreign-sapphire•2w ago
What do you need the context provider for?
quickest-silver•2w ago
Apologies, I cannot share my work project, but I can share the folder structure we use
Each of these files is purely in the format
And finally, in the
src/spi/index.ts file we have an object with all options that matches the folder structure, just for the ability to import one object and get intellisense for all endpoints in the application:
To make a query this means
1. create endpoint in API (normally just a fetch request with types/zod schema
2. create file with query options
3. update queryKeys object with query
3. attach query to shared query object
I somewhat agree that this can be tedious, but once you have your main endpoints made, the rate at which you are making new ones is pretty low, and this is therefore not a huge pain point (at least at my company).
With this said, I have been working on a vite plugin which would autogen a lot of this as soon as you make a .ts file in the above folder structure, but otherwise we have been doing this for 18 months now and it's generally felt fine.
Hope that helps you decide on how you want to do things on your end, or anyone else has any suggestions. At a minimum, you really just need to do the createQueryOptions step to get good ergonomics with query IMO
It's just worth noting, the "API" layer I described is not necessary if everything is already through query, you can just inline the API request. Similarly, if you are already using queryOptions for everything, you do not necessarily requre a "queryKeyTree" structure, but this does help with ensuring that "nested queries" are easy to invalidate by just invalidating the top level query key. But I think the ergonomics of having these levels of abstraction make things cleaner IMOconscious-sapphireOP•7d ago
first of all sorry for the delayed response fjsjdj got busy and in a lot of my components i need the data, although because tanstack query caches it idk if it is truly necessary. Hope you can educate me on that
THANK YOU SO MUCH FOR THIS
that is very clever and hood
how do you deal with typing an entity that comes from a query and the one used as input for a mutation
For example, when i fetch my products endpoint i get
id
name
opening_stock
stock*
category_id
category_name*
* this is data obtained via a join, aka those are not stored in the Product table per se
i have this as a the type Product
but, for example, when creating a product i cant send that information, cuz it doesnt matter
so, beacuse i am creating these types with zod schemas, the fields that are not needed for the mutation should just be in the schema but set as optionals?
productSchema= {
id: number.optional()
name: string(“must have name”)
opening_stock: number(“must have opening stock”)
stock*: number.optional()
category_id: number(“must have category id”)
category_name: number.optional()
}
type Product = z.infer<typeof productSchema>
Djjsjd sorry if it sounds stupid but i really cant get a clear answer for it
quickest-silver•7d ago
Personally, my mutations and queries have almost completely unrelated typings. Sometimes sharing a type is useful, but I find a lot of the time for separate endpoints, unless they return the exact same thing, it's easier to just define the type. And for a query, your params are obviously completely different to a mutation.
Personally, I don't define schemas for my arguments for queries/mutations, if the application is mostly type safe, then I'm happy enough with just having a type there, but you could absolutely define an input and output schema for both a query and mutation if you wanted.
---
So for your situation, I would just make a separate schema for your arguments of each query/mutation and then use the type from that, instead of trying to reuse the schema for both
conscious-sapphireOP•7d ago
THANK YOU SO MUCHH
♥️