graphql-faker icon indicating copy to clipboard operation
graphql-faker copied to clipboard

Due to how extend works we can't replace type fields

Open blackxored opened this issue 7 years ago β€’ 18 comments

So I was given this project a first try since I'm building some sort of boilerplate. I already have a schema, with (most) resolvers in place and I wanted to extend this with mock data. I'm assuming this scenario is probably not the goal for this project, but certainly seems like it can be used for it, and yet it can't. I can't replace fields within the existing types since extendSchema from graphqljs seems to complain. In this case what I'd like is to leave the schema as is, but replace the resolver instead.

Example: Original schema:

type User {
  id: ID!
  firstName: String
  lastName: String
}

Our fake schema in extend mode:

extend type User {
  firstName: String @fake(type: firstName)
  lastName: String @fake(type: lastName)
}

I would have expected the above syntax to work, and the resolver within it to return me the fake fields. I feel like I'm missing something obvious but if this isn't supported I think it should. I'd be able to help if you can point me in the right direction.

EDIT: I've done something like this in the past with addMockFunctionsToSchema from graphql-tools but obviously, that one lacks the Faker integration, and it's also hard to do proper relay connections in there. Maybe we could find a way to use it here as a last resort, but I think custom resolvers after leaving the schema in place should be the way to go.

blackxored avatar Aug 12 '17 16:08 blackxored

@blackxored I want this tool to be compliant with GraphQL spec and graphql-js so I can't change how extendSchema works. We also design extend mode to be used for applying non-breaking changes to existing GraphQL API and your use case is really different from that.

Hower, I have an idea how to accommodate your use case without introducing too much complexity into graphql-faker. In source code we have fakeSchema function that accepts schema and attaches resolvers to it. I can expose it as an NPM package so you would be able to write:

import { fakeSchema } from 'graphql-faker';
import { makeExecutableSchema } from 'graphql-tools';
const typeDefs = `
  type User {
    id: ID!
    firstName: String @fake(type: firstName)
    lastName: String @fake(type: firstName)
  }
`;
const resolvers = {
  User: {
     id() {
        // ...
     }
  }
};
const executableSchema = makeExecutableSchema({
  typeDefs,
  resolvers,
});

// Assing missing resolvers
fakeSchema(executableSchema);

// Pass executableSchema to your server

Will it solve your use case?

IvanGoncharov avatar Aug 12 '17 18:08 IvanGoncharov

Seems we need to keep multiple version of schema in this case, maybe we could added a "patcher" function.

In fact, I've just defined another fake version of the exact same type and append it onto the end of the original schema, and it works...like:

type Post {
  id: ID!
  article: String!
}

type Post {
  id: ID! @fake(type: uuid)
  article: String! @fake(type: lorem, options: {loremSize: paragraphs})
}

by the way, I find this "fakeSchema" :+1: solves my issue: https://github.com/APIs-guru/graphql-faker/pull/32

liuchong avatar Oct 16 '17 09:10 liuchong

Seems we need to keep multiple version of schema in this case, maybe we could added a "patcher" function.

@liuchong All GraphQL tools (including graphql-tools) I'm aware of will silently ignore unknown directives, so you can safely use one schema.

by the way, I find this "fakeSchema" πŸ‘ solves my issue: #32

Implementing it requires me to switch from custom fork of graphql-js to official version + a lot of refactoring. I plan to start working on v2.0.0 release next month. I will ping you after initial refactoring is done so you could help with PR if you have time for it.

IvanGoncharov avatar Oct 16 '17 10:10 IvanGoncharov

@IvanGoncharov Great, thanks!

liuchong avatar Oct 16 '17 11:10 liuchong

This is unfortunately a deal-breaker for us, I would love to use this package but not being able to return mock data for existing fields is very annoying. Is there any workaround for this nowadays?

mxstbr avatar Apr 30 '19 10:04 mxstbr

@mxstbr Do you want to mock the entire GraphQL API or just to use the proxy mode where some data are coming from actual API and some are mocked locally?

How about @override directive, e.g.:

extend type Post {
  acticle: String! @override @fake(type: lorem, options: {loremSize: paragraphs})
}

Will it work in your use case?

IvanGoncharov avatar Apr 30 '19 12:04 IvanGoncharov

just to use the proxy mode where some data are coming from actual API and some are mocked locally

That's what I want!

# Remote schema
type User {
  username: String!
}
# Local schema
extend type User {
  # ...some more fields...
  username: String! @fake(type: username)
}

Sounds like @override would work for my use case but I am not sure why I even need to manually specify thatβ€”if it's in the local schema, just override it instead of throwing an error?!

mxstbr avatar Apr 30 '19 12:04 mxstbr

just override it instead of throwing an error?!

@mxstbr In this case, we are changing the behavior of extend as defined in GraphQL specification and implemented in any other GraphQL tool/lib. So I don't want to enable this functionality by default. How about using --override CLI Flag instead of individually marking fields?

IvanGoncharov avatar Apr 30 '19 13:04 IvanGoncharov

That sounds great to me!

mxstbr avatar Apr 30 '19 13:04 mxstbr

@IvanGoncharov Are @override or --override available ATM?

ahmedlhanafy avatar May 06 '19 01:05 ahmedlhanafy

@ahmedlhanafy Not ATM, it's just a proposed solution. I will try to find time to implement it this month

IvanGoncharov avatar May 06 '19 08:05 IvanGoncharov

Maybe I'm misunderstanding significantly πŸ˜† , but why would you want to define new fields via extend that don't exist in your original (remote) schema?

I would think that that main use case for this library is to mock existing schema field data?

πŸ‘€

adaam2 avatar Apr 23 '20 09:04 adaam2

@IvanGoncharov Any update?

sscotth avatar Apr 28 '20 08:04 sscotth

@adaam2 I'd like to use graphql-faker to mock the api for new features so the front end can implement a feature without all backend work being done. Sometimes new features require adding fields to existing types. For example, after creating a new Course type, I'd want to add a courses field to Contact:

type Course {
  id: ID! @fake(type: uuid)
  title: String @fake(type: word)
  description: String @fake(type: lorem)
}

extend type Contact {
  courses: [Course!] @listLength(min: 1, max: 1)
}

steezeburger avatar Jul 21 '20 21:07 steezeburger

@steezeburger fair enough, but i think there's a place for both use cases here :)

adaam2 avatar Jul 22 '20 09:07 adaam2

Wouaou... this issue was open back in 2017 and there is still no solution? It's a pretty common use case, judging by the people who interacted on this thread.

I am also looking at the @override or { fakeSchema } solution -

Sincerely

orefalo avatar Aug 02 '20 17:08 orefalo

@IvanGoncharov would like to check if you will have time to look at this any soon. Thx

rostislav-simonik avatar Oct 11 '20 08:10 rostislav-simonik

This is exactly my use case as well. Have an existing GraphQL schema from a Hasura instance that I want to use to generate faked seed data to feed into mutations.

supaspoida avatar Mar 11 '21 01:03 supaspoida

I made NPM module based on my PR which enables fields overriding. If you need this feature in main module, you can subscribe to my PR's notifications and use my fork-module until it gets merged.

https://www.npmjs.com/package/@proscom/graphql-faker

hotsezus avatar Mar 15 '21 06:03 hotsezus