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.88k stars 1.34k forks source link

Generating react-apollo types for graphql import #1708

Closed chrisbrooks closed 5 years ago

chrisbrooks commented 5 years ago

Is it possible to generate types when you are using react-apollo as I am below. I do this to split out my component from the data source as a HOC.


import { graphql, compose } from 'react-apollo';
import { get } from 'lodash-es';

import { Type, showToast } from 'components/Toast/Toast.dux';
import VALIDATE_CARD_MUTATION from './graphql/validateCardMutation.graphql';
import ValidateUserForm from './ValidateCardForm';

const validateUserMutation = graphql(VALIDATE_CARD_MUTATION, {
  props: ({ ownProps, mutate }: { ownProps: { showToast: Function }; mutate?: any }) => ({
    validateCard: (access: { access: { accessCode: number; id: string } }) =>
      mutate({
        variables: {
          access,
        },
      })
        .then((response: object) => response)
        .catch((error: object) => {
          ownProps.showToast(
            Type.ERROR,
            get(error, 'graphQLErrors[0].message', 'An error occurred while signing up for an account')
          );
        }),
  }),
});

const withRedux = connect(
  null,
  (dispatch) => ({
    showToast: (type: string, message: string) => dispatch(showToast(type, message)),
  })
);

export default compose(
  withRedux,
  validateUserMutation
)(ValidateUserForm);```
dotansimha commented 5 years ago

Hi @chrisbrooks ! I'm not sure I'm getting the issue here, can you please elaborate?

If you wish to generate ready-to-use components from your .graphql file, you can do it with typescript-react-apollo plugin - you can choose between a Component, HOC or hooks. Then just use it directly instead of importing from a .graphql file.

cryptic-mystic commented 5 years ago

@dotansimha I may be mistaken, but it sounds like @chrisbrooks is looking for codegen that uses the graphql wrapper from react-apollo rather than using the withMutation or withQuery helpers.

In my scenario, the addition of the graphql util would allow me to integrate codegen with LoonaJs, which extends the graphql HOC to offer more scalable mutation update support and local state solutions.

If I'm not mistaken the generic type configurations for graphql are similar to the other utils that are already implemented.

dotansimha commented 5 years ago

Thank you @TheCrow1213 . @ardatan can you please take a look and see if we can support this use case? (Also, tagging @kamilkisiela for Loona)

veeramarni commented 5 years ago

@dotansimha I have tested it and noticed now I have something like ValidateUserFormMutationFn generated. Where that should be used as it is just a type?

For below one, if I use generated HoC wrapper function, I still see type problems.

const Component = withValidateUser({
  props: ({ mutate }) => ({
    validateCard: ({ resource }) => mutate({ variables: { resource } }),
  }),
});

Type Error

types.d.ts(68, 13): The expected type comes from the return type of this signature.
dotansimha commented 5 years ago

@veeramarni I think you can't use d.ts in this case, you need .ts (because it contains more than just declarations).

veeramarni commented 5 years ago

@dotansimha I was using generated .tsx and have this problem. It throws that none of the types matches.

veeramarni commented 5 years ago

Seems like I haven't copied full error. Here is the error.

        Type '{ validateCard: ({ resource }: { resource: any; }) => Promise<void | FetchResult<ValidateCardQuery, Record<string, any>, Record<string, any>>>; }' provides no match for the signature '(options?: MutationOptions<RemoveChangedEventMutation, ValidateCardMutationVariables>): Promise<void | FetchResult<ValidateCardMutation, Record<string, any>, Record<string, any>>>'.ts(2322)

types.d.ts(68, 13): The expected type comes from the return type of this signature.
dotansimha commented 5 years ago

@veeramarni If you are using .tsx extension for your generated file, so I'm not getting why you had errors from types.d.ts file? Please share your codegen.yml config file, and you schema and queries (if possible, in a repository with a reproduction)

veeramarni commented 5 years ago

Here is the sample code, can the graphql(...) be generated as well with types instead of manually add them like below?

https://github.com/cdmbase/fullstack-pro/blob/master/packages-modules/counter/browser/src/apollo-server-n-client/containers/Counter.tsx#L57

CodeGen file

https://github.com/cdmbase/fullstack-pro/blob/master/packages-modules/counter/codegen.yml

Generated Code

https://github.com/cdmbase/fullstack-pro/blob/master/packages-modules/counter/browser/src/apollo-server-n-client/generated-model.tsx

We want a non-react file generated seperately so we generated at a different location as below. https://github.com/cdmbase/fullstack-pro/blob/master/packages-modules/counter/browser/src/common/generated-models.ts

dotansimha commented 5 years ago

@veeramarni that's exactly what typescript-react-apollo does, it generates HOC (or Component, or Hooks) for usage with React, and it comes with a built-in typings (use withComponent: false, withHooks: false, withHOC: true config to get that).

You can use near-operation-file preset (see website for docs) in order to generate a file per each operation.

veeramarni commented 5 years ago

@dotansimha I have tried with withHOC: true but it only generates withApollo(component) but not with graphql() function. graphql() functions gives additional feature support which withApollo doesn't provide.

LeviSchuck commented 5 years ago

I am interested in a plugin that generates typeDefs, which are DocumentNode or DocumentNode[] of schemas for use with Apollo servers, be it lambda, express, or others.

So far all I can find is generating DocumentNodes for client frameworks, such as react, angular, and stencil.

import { ApolloServer } from 'apollo-server-lambda';
import resolvers from './my-code/resolvers'
// vvvv
import typeDefs from './generated/typeDefs';
// ^^^^

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

export const graphqlHandler = server.createHandler({
  cors: {
    origin: '*',
    credentials: true,
  },
});
ardatan commented 5 years ago

@LeviSchuck You can use graphql-import-node https://github.com/ardatan/graphql-import-node

LeviSchuck commented 5 years ago

@ardatan I was hoping something closer to compile time like what this project offers

veeramarni commented 5 years ago

@dotansimha Can you confirm whether graphql() function is implemented as I can see them generated?

LeviSchuck commented 5 years ago

I figured out something for me.

typescript-schema.js in the root directory with

const { printSchema } = require('graphql');
const graphqlTag = require('graphql-tag');
var gql = graphqlTag.gql;

if (!gql) {
  // For some reason loading graphql-tag was inconsistent for me
  const apolloServerCore = require('apollo-server-core');
  gql = apolloServerCore.gql;
}

module.exports = {
  plugin: (schema) => {
    const printed = printSchema(schema);
    const typeDefs = gql(printed);
    if (typeDefs.loc) {
      delete typeDefs.loc;
    }
    return `
import { DocumentNode } from 'graphql';

const typeDefs = ${JSON.stringify(typeDefs, null, 2)} as DocumentNode;
export {
  typeDefs,
};
    `;
  }
}

and then in my codegen.yml

generates:
  src/generated/schema.ts:
      - "typescript-schema.js"

Now I can do

import { typeDefs } from './generated/schema'
// ...
const server = new ApolloServer({
  typeDefs,
  resolvers,
});
dotansimha commented 5 years ago

@LeviSchuck This is implemented in: https://github.com/dotansimha/graphql-code-generator/pull/2098

dotansimha commented 5 years ago

Fixed in 1.4.0 🎉