Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type extension does not work #42

Closed
pie6k opened this issue Jan 11, 2018 · 20 comments
Closed

Type extension does not work #42

pie6k opened this issue Jan 11, 2018 · 20 comments

Comments

@pie6k
Copy link

pie6k commented Jan 11, 2018

Assume

main.graphql

# import * from "./User.graphql"
type Query {
  apiVersion: String!
}

User.graphql

type User {
  name: String!
}
extend type Query {
  me: User!
}

In resulting compiled schema Query has only version. There is no me field added.

@kbrandwijk
Copy link
Contributor

This is a limitation coming from graphql: graphql/graphql-js#922. I believe that extend definitions should be taken into consideration, but there has not been any recent activity on actually making that happen.

@huv1k
Copy link

huv1k commented Jan 15, 2018

I would like it too, it could be great feature 👍

@marktani
Copy link

A similar but different use case is extending imported types (like User) by a field:

# import * from "./User.graphql"
extend type User {
  extraField: String!
}

Does this work?

@kbrandwijk
Copy link
Contributor

kbrandwijk commented Jan 15, 2018

No that's the same situation. The extend definition is simply ignored by graphql when we read in the schema. This is something that needs to be implemented by graphql-js first. We use parse() from graphql to read in the schema.

@schickling
Copy link
Contributor

@IvanGoncharov any idea when this functionality will land?

@pie6k
Copy link
Author

pie6k commented Jan 15, 2018

Good use case of this could be having many files in project extending query and mutation type as it would lead to well organized, modular files structure.

@mwoelk
Copy link
Contributor

mwoelk commented Jan 16, 2018

Right now we can simulate the behavior at least for Query-, Mutation- and Subscription-Type by importing like:

# import Query.* from a.graphql
# import Query.* from b.graphql

Take a look at the following test cases:

@IvanGoncharov
Copy link

@IvanGoncharov any idea when this functionality will land?

@schickling As always then somebody implements it 😄
Note: graphql/graphql-js#1199 introduce a big change in how extend works so it's better to wait until it either merged or rejected.

@divyenduz
Copy link
Contributor

Another use case for this would be to extend and add "future" stuff (say, that Prisma is yet to implement like https://github.com/graphcool/prisma/issues/60).

Currently, I am copying the original type from prisma.graphql and adding "future" fields to it but this will make that chunk of code more beautiful 👍

@mjdickinson
Copy link

I need this too. I have managed to work around by just loading .graphql files myself and passing an array of strings to makeExecutableSchema() (and using extend type Query etc. to avoid multiple declaration errors). graphql-tools and graphql seem to handle the type extensions fine.

@ACollectionOfAtoms
Copy link

ACollectionOfAtoms commented Feb 8, 2018

I got around this in the following way (though it may be a pain to refactor once extend is fixed up):

in A.graphql

type A {
    name: String!
}

type Query { # notice all we have to do is omit 'extend'
   AbyName(name: String!): A
}

in schema.graphql

# import * from 'A.graphql'
# and import the whole thing as above

type Query {
   someRootQuery(thing: String!): A
}

So this way each file can be modular in that they will contain all their own Querys and Mutations etc.

@Grmiade
Copy link

Grmiade commented May 19, 2018

Any news about extend compatibility in this package?

...
import { importSchema } from 'graphql-import'

const server = new GraphQLServer({
    context,
    resolvers: {
      Employee: {
        test: () => 'okok',
      },
      Query: {
        employee: (_root, args, context, info) => {
          return context.myBinding.query.employee(args, info)
        },
      },
    },
    typeDefs: [importSchema('./src/schema.graphql'), `extend type Employee { test: String }`],
  })

If I use extend feature outside the graphql-import scope, it works

@james-ff
Copy link

I think @Grmiade has correctly identified the issue in the last comment. In my use case I am following guides on merging schemas https://www.apollographql.com/docs/graphql-tools/schema-stitching.html. This requires a typeDefs definition that only contains 'extend type' blocks to effectively bridge two schemas.

const linkTypeDefs = `extend type FirstSchemaEntity { test: SecondSchemaEntity }`

When used in literal form as in the above comment it works. But it doesn't work and errors when the extend typeDefs definition is imported via importSchema, in the below example.

const linkTypeDefs = importSchema('./linkTypeDefs.graphql')

@JulienKode
Copy link

Any update or workaround ?

@craigcbrunner
Copy link

This is what I am doing as a workaround.. it really sucks, I wish they would fix this.

const importedTypeDefs = importSchema(path.join(__dirname, '/schema.graphql'));
// stupidly type extensions can only go in here right now..
const typeDefs = gql`
      ${importedTypeDefs}
      extend type ExtendedType {
        extendedProp: String
      }
    `;

@nfantone
Copy link

nfantone commented Feb 5, 2019

@mwoelk mentioned:

Right now we can simulate the behavior at least for Query-, Mutation- and Subscription-Type

This is coming from this particular definition of which types are considered "root fields".

Here's an idea to ease some of the pain points introduced by trying to do type extension: allow users to modify or extend that rootFields array by defining "custom" root fields that would get the same "merging" behaviour as Query et al.

// "Viewer" is a custom type
const schema = importSchema('./schema.graphql', { rootFields: ['Viewer'] });

This would be particularly useful in scenarios like Relay's Viewer type, where most queries are defined as a field on a viewer. Below is a full example.

# foo.graphql

type Foo implements Node { ... }

type Viewer {
  fooQuery(id: ID!): Foo!
}
# bar.graphql

type Bar implements Node { ... }

type Viewer {
  barQuery(id: ID!): Bar!
}
# relay.graphql

type Query {
  viewer: Viewer!
  node(id: ID!): Node
}

interface Node {
  id: ID!
}

type Viewer {
  id: ID!
}

And the root (schema.graphql) schema could look like:

# import Query.*, Viewer.* from "./relay.graphql"
# import Viewer.* from "./bar.graphql"
# import Viewer.* from "./foo.graphql"

Which would produce the following final SDL:

interface Node {
  id: ID!
}

type Bar implements Node { ...}

type Foo implements Node { ...}

type Query {
  viewer: Viewer!
  node(id: ID!): Node
}

type Viewer {
  id: ID!
  barQuery(id: ID!): Bar!
  fooQuery(id: ID!): Foo!
}

What do you think? I could put together a simple PR for this, if you are up to.

@entrptaher
Copy link

entrptaher commented May 13, 2019

I am doing a weird hack for experiment,

const server = new GraphQLServer({
  typeDefs: [
    "src/generated/prisma.graphql",
    fs.readFileSync("./src/schema.graphql", "utf-8")
  ],
  resolvers,
  context: {
    prisma
  }
});

datamodel.prisma
image

schema.graphql

extend type Query {
  feed: [Post!]!
  drafts: [Post!]!
}

extend type Mutation {
  createDraft(title: String!, content: String): Post
  publish(id: ID!): Post
}

It works as expected, I have all queries and mutations from generated graphql file and the extended queries as well. See below,

image

The problem with this approach is,

  • I cannot use import inside the schema.graphql file
  • I cannot overwrite any query/mutation that's already defined
  • I cannot hide a certain field, say hashed password.

So what I was looking for,

  • To import normally.
  • To overwrite and customize something.
  • To hide a certain field if I needed.

It would increase modularity and reduce code duplication is so many levels. Specially I wouldn't have to end up copy pasting the schema in multiple places.

@ardatan
Copy link
Owner

ardatan commented Dec 31, 2019

Hi @pie6k !
In 1.0.0 beta release, we introduced a lot of changes including extensions support in type definitions. This was an issue we were struggling in GraphQL Toolkit and we fixed it. Since GraphQL Import uses GraphQL Toolkit behind the scenes. The issue should be gone.

Could you install graphql-import@beta to try new changes? Don't forget to modify your code regarding to the migration notes in README.
https://github.com/ardatan/graphql-import#updating-from-07x

@yanko-ivanov
Copy link

yanko-ivanov commented Jan 28, 2020

@ardatan Hey. I just stumbled onto the problem. Using ^1.0.0-beta.2, I have the following files:
0.Query.graphql (Named weirdly as to be loaded first, otherwise it doesn't even recognize the Query type. Irrelevant to this topic tho)

type Query {
   cities: [City]
}

City.graphql

type City {
    id: ID!
    name: String!
}

extend type Query {
    getCity(id: ID): City
}

Now... the behaviour I'm getting, is that if the extend is in City.graphql, it's not recognized, judging by me dumping the typeDefs in the importSchema() promise.
If the extend is in Query.graphql, it gets recognized and imported correctly into the Query type.

Edit: I'm using apollo-server with express, if that's relevant.

@ardatan
Copy link
Owner

ardatan commented Mar 17, 2020

Available in 1.0.0!

@ardatan ardatan closed this as completed Mar 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests