dotansimha / graphql-code-generator

A tool for generating code based on a GraphQL schema and GraphQL operations (query/mutation/subscription), with flexible support for custom plugins.
https://the-guild.dev/graphql/codegen/
MIT License
10.86k stars 1.33k forks source link

Generate mock query with `fragment-masking` #9687

Open marromugi opened 1 year ago

marromugi commented 1 year ago

Is your feature request related to a problem? Please describe.

I want to generate mock data with fragment-masking and msw

related comminity plugin

Describe the solution you'd like

  1. add type for reveal fragment-masking sample code is here
    
    type FragmentRef = { " $fragmentRefs"?: { [key in string]: any } } | null;

export type FragmentRevealer = Omit<T, " $fragmentRefs"> & T extends { " $fragmentRefs"?: { [key in string]: infer TFragment }; } ? TFragment extends { " $fragmentName"?: string } ? Omit<TFragment, " $fragmentName"> : TFragment : T;

export type QueryRevealer<T extends { [key in string]: any }> = {

};

// query wrapping export const mockTeamCardQuery = ( resolver: ResponseResolver< GraphQLRequest, GraphQLContext<QueryRevealer>, any

, ) => graphql.query<QueryRevealer, TeamCardQueryVariables>("TeamCard", resolver);

// I can define data without $fragmentRef mockTeamCardQuery((req, res, ctx) => { return res( ctx.delay(1000), ctx.data({ team: { typename: "Team", id: 3, uid: "11", name: "Team", }, currentUser: { typename: "User", name: "User", }, }), ); }),

// if I don't use QueryRevealer, I need to define data like below mockTeamCardQuery((req, res, ctx) => { return res( ctx.delay(1000), ctx.data({ team: { typename: "Team", id: 3, " $fragmentRefs": { TeamCardProfileFragment: { typename: "Team", id: 1, uid: "abc", name: "TeamName", }, }, }, currentUser: { typename: "User", " $fragmentRefs": { TeamCardUserFragment: { typename: "User", name: "Me", }, }, }, }), ); }),


2. add `fragment-revealer` option to `typescript-mock-data` config
add config  if you adopt above type `QueryRevealer` to `mockXXXQuery`s type or not
https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-mock-data

### Describe alternatives you've considered

_No response_

### Is your feature request related to a problem? Please describe.

Thank you for amazing library!

I want to generate mock data for develop in local env by using msw.

To generate mock data, we can use below library `typescript-mock-data`.
https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-mock-data

But, if I use the library with `fragment-masking(including client-preset)`, I can't cache response because response type is different from defined type created by `typescript-mock-data`.

Generated mockQuery`s type is below
```ts
export type TeamCardProfileFragment = {
  __typename?: "Team";
  id: number;
  uid: string;
  name: string;
} & { " $fragmentName"?: "TeamCardProfileFragment" };

// query type
export type TeamCardQuery = {
  __typename?: "Query";
  team:
    | ({ __typename?: "Team"; id: number } & {
        " $fragmentRefs"?: { TeamCardProfileFragment: TeamCardProfileFragment };
      })
    | null;
};

// query mock
export const mockTeamCardQuery = (
  resolver: ResponseResolver<
    GraphQLRequest<TeamCardQueryVariables>,
    GraphQLContext<TeamCardQuery>,
    any
  >,
) => graphql.query<TeamCardQuery, TeamCardQueryVariables>("TeamCard", resolver);

I can use query mock like below

mockTeamCardQuery((req, res, ctx) => {
          return res(
            ctx.delay(1000),
            ctx.data({
              team: {
                __typename: "Team",
                id: 3,
                " $fragmentRefs": {
                  TeamCardProfileFragment: {
                    __typename: "Team",
                    id: 1,
                    uid: "abc",
                    name: "TeamName",
                  },
                },
              },
            }),
          );
        }),

I can define mock like above, but graphql client ( urql ) doesn't cache mock response because the response is dfferent from expected response. $fragmentRefs is used for improving type strictness on coding, so it is better to exclude $fragmentRefs from mock query's data.

To solve this problem, we need to fix some code in fragment-masking and typescript-mock-data. I understand it might be a bit challenging, but I would appreciate it if you could consider it.

bolyesz commented 5 months ago

Did you manage to solve it by any chance ?