prisma-labs / graphqlgen

⚙️ Generate type-safe resolvers based upon your GraphQL Schema
MIT License
817 stars 56 forks source link

Import typescript file in schema: Syntax Error: Cannot parse the unexpected character "." #436

Open devautor opened 5 years ago

devautor commented 5 years ago

How do I import a typescript file as the schema in graphqlgen configuration.

I am using graphql-code-generator to generate types from my schema using: schema: http://localhost:4000/graphql Then, as I am trying to use graphqlgen to generate resolvers from these generated types and the schema.

I am getting this error:

G:\server\prod\apollo-server>graphqlgen
Error occurred while reading schema: Syntax Error: Cannot parse the unexpected character ".".

GraphQL request (1:1)
1: ./src/makeExecutableSchema.ts
   ^

G:\server\prod\apollo-server>

My graphqlgen.yml is:

# The target programming language for the generated code
language: typescript

# The file path pointing to your GraphQL schema
schema: ./src/makeExecutableSchema.ts

# Type definition for the resolver context object
context: ./src/context.ts:Context

# Map SDL types from the GraphQL schema to TS models
models:
  files:
    #- ./src/generated/prisma-client-ts/index.ts
    - ./src/types.d.ts

# Generated typings for resolvers and default resolver implementations
# Please don't edit this file but just import from here
output: ./src/generated/graphqlgen.ts

# Temporary scaffolded resolvers to copy and paste in your application
resolver-scaffolding:
  output: ./src/generated/tmp-resolvers/
  layout: file-per-type
jasonkuhrt commented 5 years ago

👋

Can you share the contents of ./src/makeExecutableSchema.ts?

devautor commented 5 years ago

Hello @jasonkuhrt Sure, here is my ./src/makeExecutableSchema.ts:

/**
 * Makes executable schema for Apollo server API
 * from typedefs and resolvers, and adds permissions middleware
 */

import { makeExecutableSchema } from "apollo-server";
import typeDefs from "./schema";
//import { resolvers } from "./resolvers";
// import all scalar resolvers
import OKGGraphQLScalars from "@okgrow/graphql-scalars";

import { applyMiddleware } from "graphql-middleware";
//import permissions from "./auth/permissions";

const schema = makeExecutableSchema({
  typeDefs: typeDefs,
  resolvers: {
    ...OKGGraphQLScalars
  }
});

// with auth permission middleware, using graphql-shield
export default () => {
  // console.log(`Applying permissions middleware...`);
  // return applyMiddleware(schema, permissions);
  return applyMiddleware(schema);
};

And, here is my ./src/schema.ts:

// Graphql schema of the server API

import { gql } from "apollo-server";
// import all scalars
import { OKGScalarDefinitions } from "@okgrow/graphql-scalars";

// importing typescript files, each is gql`...` extending types Query, Mutation, Subscription
import sharedSchema from "./schema/shared";  
import postSchema from "./schema/post";
import storeSchema from "./schema/store";
import customerSchema from "./schema/customer";
import collectionSchema from "./schema/collection";
import productVariantSchema from "./schema/productVariant";

const blankSchema = gql`
  type Query {
    _blank: String
  }

  type Mutation {
    _blank: String
  }

  type Subscription {
    _blank: String
  }
`;

const schema = [
  blankSchema,
  ...OKGScalarDefinitions,
  sharedSchema,
  postSchema,
  storeSchema,
  customerSchema,
  collectionSchema,
  productVariantSchema
];

export default schema;
jasonkuhrt commented 5 years ago

schema: ./src/makeExecutableSchema.ts

Should be

schema: ./src/schema.ts

devautor commented 5 years ago

Thanks for the reply @jasonkuhrt but that too gives the same error.

Error occurred while reading schema: Syntax Error: Cannot parse the unexpected character ".".

GraphQL request (1:1)
1: ./src/schema.ts
jasonkuhrt commented 5 years ago

@devautor thanks for confirming, it is a step in the right direction.

Are you using at least 0.6.0-rc4. Only starting from that version was it possible to import from TypeScript files.

devautor commented 5 years ago

Thanks @jasonkuhrt for your patience! Yes, I am using "graphqlgen": "^0.6.0-rc4" (copied from package.json).

jasonkuhrt commented 5 years ago

@devautor same to you :) I'll try to take a closer look at this tonight or failing that in the coming days.

devautor commented 5 years ago

Oh, sure! I hope you could find time for this tonight, or sooner than later (I have my timeline set to "Write resolvers" from today tomorrow). [I understand that you must have n things to do :) ]

jasonkuhrt commented 5 years ago

Hey @maticzav on your end are you experiencing any issues having graphqlgen get schema from your TS module?

devautor commented 5 years ago

Hi @jasonkuhrt Thank you so much for your fix; but I am not able to get it running still, am I doing something wrong here:

G:\apollo\prod\apollo-server>npm i -D graphqlgen
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.7 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.7: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ graphqlgen@0.6.0-rc5
updated 2 packages in 17.991s

G:\apollo\prod\apollo-server>graphqlgen
Error occurred while reading schema: Syntax Error: Cannot parse the unexpected character ".".

GraphQL request (1:1)
1: ./src/schema.ts
   ^

G:\apollo\prod\apollo-server>graphqlgen
Error occurred while reading schema: Syntax Error: Cannot parse the unexpected character ".".

GraphQL request (1:1)
1: ./src/makeExecutableSchema.ts
   ^

G:\apollo\prod\apollo-server>
jasonkuhrt commented 5 years ago

I only just published the new version. Give 0.6.0-rc6 a try.

devautor commented 5 years ago

Sorry @jasonkuhrt my bad! Trying with rc6 is still producing the same error to me:

G:\apollo\prod\apollo-server>npm i -D graphqlgen
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.7 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.7: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ graphqlgen@0.6.0-rc6
added 1 package and updated 2 packages in 29.478s

G:\apollo\prod\apollo-server>graphqlgen
Error occurred while reading schema: Syntax Error: Cannot parse the unexpected character ".".

GraphQL request (1:1)
1: ./src/makeExecutableSchema.ts
   ^

G:\apollo\prod\apollo-server>graphqlgen
Error occurred while reading schema: Syntax Error: Cannot parse the unexpected character ".".

GraphQL request (1:1)
1: ./src/schema.ts
   ^

G:\apollo\prod\apollo-server>
jasonkuhrt commented 5 years ago

Can you show me the output of:

cat ./src/schema.ts

And then, what happens if you try this:

# update your graphqlgen.yml to have this field:
schema: test-schema.graphql
> echo 'type Query {\n  a: String\n} > test-schema.graphql
> graphqlgen
devautor commented 5 years ago

Hello @jasonkuhrt I had shared src/schema.ts above, should I paste it here again? Also, following steps you have asked to test with a graphql file, I do get successful generation:

src/test-schema.graphql is:

type Query {
  a: String
}

graphqlgen.yml is:

# The target programming language for the generated code
language: typescript

# The file path pointing to your GraphQL schema
#schema: ./src/schema.ts
schema: ./src/test-schema.graphql

# Type definition for the resolver context object
context: ./src/context.ts:Context

# Map SDL types from the GraphQL schema to TS models
models:
  files:
    #- ./src/generated/prisma-client-ts/index.ts
    - ./src/types.d.ts

# Generated typings for resolvers and default resolver implementations
# Please don't edit this file but just import from here
output: ./src/generated/graphqlgen.ts

# Temporary scaffolded resolvers to copy and paste in your application
resolver-scaffolding:
  output: ./src/generated/tmp-resolvers/
  layout: file-per-type

Output is:

G:\apollo\prod\apollo-server>graphqlgen
Resolver interface definitons & default resolvers generated at ./src/generated/graphqlgen.ts
Resolvers scaffolded at ./src/generated/tmp-resolvers/

G:\apollo\prod\apollo-server>

For completeness, I did cat src/schema.ts and am getting what's supposed:

kgj@DESKTOP-4VQE7EO:/mnt/g/apollo/prod/apollo-server$ cat src/schema.ts
// Graphql schema of the server API

import { gql } from "apollo-server";
// import all scalars
import { OKGScalarDefinitions } from "@okgrow/graphql-scalars";

// importing typescript files, each is gql`...` extending types Query, Mutation, Subscription
import sharedSchema from "./schema/common";
import postSchema from "./schema/post";
import storeSchema from "./schema/store";
import customerSchema from "./schema/customer";
import collectionSchema from "./schema/collection";
import productVariantSchema from "./schema/productVariant";
import addressSchema from "./schema/address";

const blankSchema = gql`
  type Query {
    _blank: String
  }

  type Mutation {
    _blank: String
  }

  type Subscription {
    _blank: String
  }
`;

const schema = [
  blankSchema,
  ...OKGScalarDefinitions,
  sharedSchema,
  postSchema,
  storeSchema,
  customerSchema,
  collectionSchema,
  productVariantSchema,
  addressSchema
];

export default schema;
maticzav commented 5 years ago

hey @devautor 👋 Could you briefly explain how the list as a schema thing works? I haven’t seen it before but it looks very interesting.

@jasonkuhrt, graphqlgen generates types correctly in my project. Haven’t pushed it yet though.

devautor commented 5 years ago

Hey @maticzav a fan here :) I am following the docs for graphql-tools (Apollo server) from here: "typeDefs is a required argument and should be an GraphQL schema language string or array of GraphQL schema language strings ... The order of the strings in the array is not important, but it must include a schema definition."

Kindly let me know if I have done something lazy here :)

P.S. BTW I was about to message you on twitter regarding graphql-shield :)

jasonkuhrt commented 5 years ago

@devautor since I don't have access to your project, and since you now have a hyper-minimal example schema working, can you start from the tester I gave you and incrementally make it be like yours, testing graphqlgen each time, the idea being we'll get a pinpoint on exactly what causes your case to break.

devautor commented 5 years ago

@jasonkuhrt I recall that the minimal example I got working was from a graphql file, and couldn't get one working from a ts file. But, I understand and appreciate your point. I will try to do that (maybe it could take time, since I am pressed down by a huge schema :) )

jasonkuhrt commented 5 years ago

@devautor what happens with (ts version):

> echo 'type Query {\n  a: String\n} > test-schema.ts
> graphqlgen
devautor commented 5 years ago

@jasonkuhrt I am sorry that I didn't report that... Here's what I get:

G:\apollo\prod\apollo-server>graphqlgen
Error occurred while reading schema: Syntax Error: Cannot parse the unexpected character ".".

GraphQL request (1:1)
1: ./src/test-schema.ts
   ^

G:\apollo\prod\apollo-server>

My test-schema.ts is:

import { gql } from "apollo-server";

const typeDefs = gql`
  type Query {
    a: String
  }
`;

export default typeDefs;

And, my graphqlgen.yml is:

# The target programming language for the generated code
language: typescript

# The file path pointing to your GraphQL schema
#schema: ./src/schema.ts
schema: ./src/test-schema.ts

# Type definition for the resolver context object
context: ./src/context.ts:Context

# Map SDL types from the GraphQL schema to TS models
models:
  files:
    #- ./src/generated/prisma-client-ts/index.ts
    - ./src/types.d.ts

# Generated typings for resolvers and default resolver implementations
# Please don't edit this file but just import from here
output: ./src/generated/graphqlgen.ts

# Temporary scaffolded resolvers to copy and paste in your application
resolver-scaffolding:
  output: ./src/generated/tmp-resolvers/
  layout: file-per-type
jasonkuhrt commented 5 years ago

It’s as if graphqlgen is trying to parse the path to the file, rather than the file contents.

I haven’t been able to repro. Can you make a small repo or code sandbox where I can interact with the repro myself?

devautor commented 5 years ago

Hi @jasonkuhrt I have a mini-reproduction on my local system, my free codesandbox limit is up. Please allow me some time.

EDIT: Hello again @jasonkuhrt and @maticzav I have reproduced and shared the issue here in this repo, kindly review https://github.com/devautor/graphqlgen-issue-reproduction :)

jasonkuhrt commented 5 years ago

@devautor thanks! Will take a look tonight

jasonkuhrt commented 5 years ago

My investigation is below. Some takeaways

git clone git@github.com:devautor/graphqlgen-issue-reproduction.git
❯ yarn
yarn install v1.13.0
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
✨  Done in 25.10s.
❯ yarn run dev
yarn run v1.13.0
$ nodemon
[nodemon] 1.18.9
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: /Users/jasonkuhrt/projects/oss/graphqlgen-issue-reproduction/src/**/*
[nodemon] starting `ts-node ./index.ts`
Apollo server created, graphql path is /graphql
Server ready at http://localhost:4000/
[nodemon] restarting due to changes...
[nodemon] starting `ts-node ./index.ts`
Apollo server created, graphql path is /graphql
Server ready at http://localhost:4000/

new shell

❯ yarn generate
yarn run v1.13.0
$ gql-gen
  ✔ Parse configuration
  ✔ Generate outputs
✨  Done in 2.96s.
❯ yarn -s graphqlgen
yarn run v1.13.0
$ /Users/jasonkuhrt/projects/oss/graphqlgen-issue-reproduction/node_modules/.bin/graphqlgen

Then I did

❯ gd
diff --git a/src/test-schema.ts b/src/test-schema.ts
index 3827ded..2530f86 100644
--- a/src/test-schema.ts
+++ b/src/test-schema.ts
@@ -1,7 +1,7 @@
 import { gql } from "apollo-server";

 const typeDefs = gql`
-  extend type Query {
+  type Query {
     a: String
   }
 `;
❯ yarn -s graphqlgen
Type definitions for your resolvers generated at ./src/generated/graphqlgen.ts
Resolvers scaffolded for you at ./src/generated/tmp-resolvers/
❯ cat ./src/generated/graphqlgen.ts
// Code generated by github.com/prisma/graphqlgen, DO NOT EDIT.

import { GraphQLResolveInfo } from "graphql";
import { Context } from "../context";

export namespace QueryResolvers {
  export const defaultResolvers = {};

  export type AResolver =
    | ((
        parent: undefined,
        args: {},
        ctx: Context,
        info: GraphQLResolveInfo
      ) => string | null | Promise<string | null>)
    | {
        fragment: string;
        resolve: (
          parent: undefined,
          args: {},
          ctx: Context,
          info: GraphQLResolveInfo
        ) => string | null | Promise<string | null>;
      };

  export interface Type {
    a:
      | ((
          parent: undefined,
          args: {},
          ctx: Context,
          info: GraphQLResolveInfo
        ) => string | null | Promise<string | null>)
      | {
          fragment: string;
          resolve: (
            parent: undefined,
            args: {},
            ctx: Context,
            info: GraphQLResolveInfo
          ) => string | null | Promise<string | null>;
        };
  }
}

export interface Resolvers {
  Query: QueryResolvers.Type;
}
devautor commented 5 years ago

Morning @jasonkuhrt A little confusion here, you wrote that "couldn't reproduce your error", and also that "removing extend made it work"; so did you get the same error as mine with extend?

Also, I am using gql-gen to generate typed model of the schema required by the graphqlgen tool (typed.d.ts). Is it unnecessary?

Regarding extend, I am following this https://www.apollographql.com/docs/graphql-tools/generate-schema.html#extend-types. Since I have to import typeDefs from multiples typescript files, if I don't use extend, I get an error saying that type Query is defined at multiple places.

Thank you for all your attention to such tiny details Jason, and do let me know what am I doing stupid here, or what should Ibdo next!

jasonkuhrt commented 5 years ago

so did you get the same error as mine with extend

No, I pasted exactly what I did and saw in my code blocks

Also, I am using gql-gen to generate typed model of the schema required by the graphqlgen tool (typed.d.ts). Is it unnecessary?

Ah I see, please chime in/upvote https://github.com/prisma/graphqlgen/issues/181 as yes I would like to make it unnecessary.

Regarding extend, I am following this https://www.apollographql.com/docs/graphql-tools/generate-schema.html#extend-types. Since I have to import typeDefs from multiples typescript files, if I don't use extend, I get an error saying that type Query is defined at multiple places.

Makes sense! I'll look more into the extend aspect.

Thanks for sharing your repro via a repo, it was very helpful!

devautor commented 5 years ago

@jasonkuhrt Upvoted that, adding that feature would be really helpful (since different tools do bring different design choices, so swapping would not be easy with a codebase as heavy as mine, I guess).

While you look into extend, do you have a suggestion or a workaround for me to get started with my pretty resolvers? :)

Thank you to you Jason for making such tools, you guys are the magic :)

jasonkuhrt commented 5 years ago

:)

As a workaround for now, if you centralize your schema so as to not need extend then it should work currently.

devautor commented 5 years ago

Oh @jasonkuhrt that'd not be so easy or desirable to me, but I am not complaining :) I would really wish to have supports for extend and auto-generated type model (mere feature requests). I do think that they serve and complete the purpose of graphqlgen.

jasonkuhrt commented 5 years ago

@devautor discovered that the reason extend does not currently work:

Also, I have not been able to repro your reported issue of:

GraphQL request (1:1)
1: ./src/test-schema.ts
   ^

Is this still what you are stuck on?

devautor commented 5 years ago

Hello @jasonkuhrt Sorry, I had missed this comment of yours! I am definitely getting the same error as reported with extend keyword in use. So, I think that you're suggesting to use graphql-import instead of .ts files to bypass this issue, right? That had worked in an earlier project of mine, so I could try that! Thank you :)

jasonkuhrt commented 5 years ago

So, I think that you're suggesting to use graphql-import instead of .ts files to bypass this issue, right?

No, to my knowledge you simply cannot use extends currently.

devautor commented 5 years ago

Oh @jasonkuhrt I see, but graphql-code-generator understands it and generates types for it (models). Note: Have just started playing with its resolvers generator, no error thrown at least! :)

EDIT: Downloaded schema.graphql that graphql-playground offers to import by introspection, and using it with graphqlgen, it doesn't terminate, stuck it gives the following error trace (out of heap memory):

G:\apollo\prod\apollo-server>graphqlgen

<--- Last few GCs --->

[28164:00000205D273F330]   360312 ms: Mark-sweep 1179.9 (1220.6) -> 1179.9 (1220.6) MB, 342.1 / 0.0 ms  allocation failure GC in old space requested[28164:00000205D273F330]   360658 ms: Mark-sweep 1179.9 (1220.6) -> 1179.9 (1186.6) MB, 346.2 / 0.0 ms  last resort GC in old space requested
[28164:00000205D273F330]   361001 ms: Mark-sweep 1179.9 (1186.6) -> 1179.9 (1186.6) MB, 342.7 / 0.0 ms  last resort GC in old space requested
<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 000002446BAA5879 <JSObject>
    0: builtin exit frame: concat(this=000003DD60626801 <JSArray[30393831]>,00000081E787F9A9 <JSArray[8603361]>)

    1: flatten(aka flatten) [C:\Users\gaurav\AppData\Roaming\npm\node_modules\graphqlgen\dist\utils.js:~49] [pc=000003129AB542C3](this=00000214B0A822D1 <undefined>,a=000003DD60626801 <JSArray[30393831]>,b=00000081E787F9A9 <JSArray[8603361]>)
    2: arguments adaptor frame: 4->2
   ...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node_module_register
 2: v8::internal::FatalProcessOutOfMemory
 3: v8::internal::FatalProcessOutOfMemory
 4: v8::internal::Factory::NewUninitializedFixedArray
 5: v8::internal::Factory::NewJSArrayStorage
 6: v8::internal::WasmDebugInfo::SetupForTesting
 7: v8_inspector::protocol::Debugger::API::SearchMatch::fromJSONString
 8: v8_inspector::protocol::Debugger::API::SearchMatch::fromJSONString
 9: v8_inspector::protocol::Debugger::API::SearchMatch::fromJSONString
10: 000003129AA06B21

G:\apollo\prod\apollo-server>

Also, for comparison, graphql-code-generator generates model types and resolvers from the same schema file successfully:

$ gql-gen
  √ Parse configuration
  √ Generate outputs
Done in 4.24s.

Should I open independent issue for this, or is this a known and fixable issue?

jasonkuhrt commented 5 years ago

Should I open independent issue for this, or is this a known and fixable issue?

There have been similar issues in the past, however presently none open I think. Feel free to open one.

I see, but graphql-code-generator understands it and generates types for it (models)

Good to know, something to review when we tackle the issue inside graphql-import. Also Apollo Server has support (clearly, since you're already doing that).

devautor commented 5 years ago

All right @jasonkuhrt I will open one issue, because I want those pretty default resolvers (grapqhl-code-generator works and is awesome too, but has higher cognitive load initially :) ).

devautor commented 5 years ago

Hi @jasonkuhrt Bad news, most of this happened because I'm lazy :) While trying to reproduce #449 I realized that I was using global install of graphqlgen (it was at 0.4.0), now when I run it locally on the same project this issue has been reported on (with schema.ts as schema import in graphqlgen.yml), I get this error instead:

Failed to parse schema: TypeError: Must provide Source. Received: ["scalar DateTime\n\nscalar JSON\n\ntype Query {\n  _blank: String\n}\n\ntype Mutation {\n  _blank: String\n}\n\ntype Subscription {\n  _blank: String\n}\n", "extend type Query {\n  \"\"\"\n  Get
an address by ID\n  \"\"\"\n  address(where: AddressWhereUniqueInput!): Address\n}\n\nextend  ... **continues**

Update: On running graphqlgen locally with schema.graphql as schema import in graphqlgen.yml, I am getting this error instead:

(node:36540) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'map' of undefined
    at Object.exports.printFieldLikeType (G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\common.js:135:52)
    at renderTypeResolver (G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\typescript\generator.js:234:31)
    at G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\typescript\generator.js:210:82
    at Array.map (<anonymous>)
    at renderResolverFunctionInterfaces (G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\typescript\generator.js:209:10)
    at renderNamespace (G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\typescript\generator.js:153:274)
    at G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\typescript\generator.js:118:16
    at Array.map (<anonymous>)
    at renderObjectNamespaces (G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\typescript\generator.js:117:10)
    at renderNamespaces (G:\graftale\prod\graftale-server\node_modules\graphqlgen\dist\generators\typescript\generator.js:112:21)
(node:36540) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:36540) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.