graphql-code-generator
                                
                                
                                
                                    graphql-code-generator copied to clipboard
                            
                            
                            
                        Support for `loader`-functionality from `@remix`/`react-router-dom`
Is your feature request related to a problem? Please describe.
With the Blog Article from Ryan Florence Remixing React Router the loader Pattern from Remix is said to move to [email protected].
I haven't found a way to populate the loader-Property with hooks
Describe the solution you'd like
I'm currently using graphql-codegen with typescript-urql and since we are generating a hook there and no awaitable fetch function we can't use the functionality of loader with Hooks yet?
I was wondering if we might find a way to generate an awaitable fetch function that calls in my context client.query based on the graphql querries which then populates the loader.
If there is any solution for this let me know, I really like to hear your opinion on this.
I could implement this. The question is what API would be best. I have few ideas
First approach would be a higher order function, loaders would pass params  as variables , and
actions would pass the formData by default.
We would also generate corresponding typed useLoaderData  and useLoaderAction hooks.
The biggest issue is formData and params being dictionaries of strings they almost always require extra parsing. We could let user set a parsing function through config, this way they could for example parse and pass request.url.search instead of params.
import { userLoader, editAction, useUserData, useEditAction } from './generated'
export const loader = userLoader()
export const action = editAction()
// optional config
export const loader = userLoader({
  requestPolicy: 'cache-and-network'
})
//with variables
export const loader = userLoader((ctx) => ({
  variables:
  {
    id: Number(ctx.params.userId),
  },
  requestPolicy: 'cache-and-network'
}))
Second approach is much simpler, it requires user to wrap the function, and write more types, the useLoaderData calls would have to be cast (useLoaderData() as LoaderData<typeof loader>)
This easily allows user to parse the results, inside the loader: throw 404, redirects etc.
import { userLoader, editAction } from './generated'
export function loader(ctx: LoaderFunctionArgs){
  return userLoader({ userId: ctx.params.userId })
}
export function action(({ request }: ActionFunctionArgs) => {
  const data = await request.formData()
  return editAction(Object.fromEntries(data))
})
I think the first approach is slightly more interesting, it is would be very powerful, with structured form data
<input name='user.id' value='1'>
<input name='user.name' value='new_name'>
(such form would be parsed into json { user: { id:1, name: 'new_name' } } by an external library).
Let me know what do you think, what are the use cases you are interested in.
I would also be interested in something like this — but I think the only gap that needs filling is action. For loader, you can just use Awaited<ReturnType<typeof loader>> and you’re good to go. (Note that you shouldn’t type loader with LoaderFunction, but instead its arguments with LoaderArgs, in order to be able to use the return type. (In TypeScript 4.9, the satisfies operator will allow to use LoaderFunction as well.))
For action, however, it’s annoying to parse request.formData() for each request. Here, I think the ideal design of autogenerated helpers is as follows:
- One function per GraphQL document. For example, 
const data = await sdk.CreateUser(formData), wheredatais the mutation responseconst sdk = getSdk(client)(equivalent togetSdkof thetypescript-graphql-requestplugin)const formData = await request.formData()
 - Each such function expects all of its variables according to the properties of the leaves of the GraphQL input type
- e.g. for 
input CreateUserInput = { firstName: String!, lastName: String! }, the autogenerated functionsdk.CreateUserwould expectformData.get('firstName')and.get('lastName')to be of the right shape, although the GraphQL mutation only has one variable: an object with keyinput. - In other words, input objects would be “flattened”, because this would be the most convenient setup when creating manual 
<input />s on the client side - Which creates the potential for naming collisions
 
 - e.g. for 
 - In case the incoming data has the wrong shape: 
throw new Response(`Invalid value for ${name}`, { status: 422 }) 
For the moment, I’m doing the validation manually. Just writing down my thoughts, in case I might revisit this decision later.