milesj / shapeshifter

🐺 Generate relational schemas, PropTypes, Flow aliases, and TypeScript interfaces from JSON or GraphQL schematic files.
MIT License
103 stars 6 forks source link

Unsupported GraphQL definition #29

Closed konsumer closed 5 years ago

konsumer commented 6 years ago

I am using a custom directive, that looks like this:

enum AuthRole {
  VERIFIED
  PAID
  ADMIN
  DEV
}
directive @auth(role: AuthRole, roles: [AuthRole]) on FIELD | FIELD_DEFINITION

I have this defined in my graphql file.

When I run shapeshifter with shapeshifter-parser-graphql, I get this error:

shapeshifter --prop-types src/generated/data-server.graphql > src/generated/data-server.props.js

Unsupported GraphQL definition "auth".

Is there a way to ignore directives?

konsumer commented 6 years ago

Also, If I comment out the @auth definition, I get

Unsupported GraphQL definition "DateTime".

for a custom scalar I have defined like this:

scalar DateTime
konsumer commented 6 years ago

I also get errors on basic input types, when I run it on this auto-generated SDL from the server.

Maybe an alternate way to deal with this would be to allow a subset of types, that was tolerant of unused definitions like:

shapeshifter --prop-types --only-types --scalar-placeholders src/generated/data-server.graphql > src/generated/data-server.props.js

if it just outputted a DateTime placeholder with a comment, and ignored directives and inputs, I think it would work really well for my use-case.

Am I just using this wrong?

konsumer commented 6 years ago

I made a demo-project to illustrate the issue with SWAPI.

milesj commented 6 years ago

@konsumer Are these all new GraphQL features? I've never seen them before.

konsumer commented 6 years ago

Custom directives and scalars are maybe a lil new, but input-types are OG, and that is what is failing in the SWAPI demo-project. I wouldn't mind too much if it just ignored the auth directive & DateTime scalar it doesn't know how to handle, and just outputted a comment or something.

Both links are apollo docs, but I think it's not super-apollo-specific, like this is output from graphql-cli's get-schema, which infers the SDL from a running server.

Without going into too much detail, the purpose of @auth for me is to make sure fields & endpoints are locked down and have the correct JWT info passed to resolvers (I'd be happy to share code, if you're curious.) DateTime is so I have a human-readable and editable format that is compatible with prisma (graphql database-layer of my app) and the type is universal all the way down the stack. I also use a Json custom scalar, in the same way.

konsumer commented 6 years ago

Also, if the simplest answer is just that I need to copy over the types I actually want, and hand-tune them for shapeshifter to deal, I don't really mind. It's only a few types.

milesj commented 6 years ago

Made some changes to no longer error on unknown things, instead it will just be a no-op. PR: https://github.com/milesj/shapeshifter/commit/906f8d45fc2b367fb5e3100c9780a0de4ebbeb27

Since there's no way to know what the underlying scalar type is, I'm currently just omitting the value all together. I'm open to suggestions on how to resolve it.

konsumer commented 6 years ago

That sounds perfect. I will try it out, and report back.

konsumer commented 6 years ago

On the demo project, I still get this error:

ENOENT: no such file or directory, open '{DIR}/shapeshifter-demo/Film.graphql'

Not sure if it's just hard-coded to expect files in same dir, or if it's having trouble with interfaces:

type Film implements Node {
  # ...
}

"""An object with an ID"""
interface Node {
  """The id of the object."""
  id: ID!
}
milesj commented 6 years ago

@konsumer Interfaces are completely ignored: https://github.com/milesj/shapeshifter/blob/master/packages/parser-graphql/src/index.ts#L266

It's probably creating a file reference here: https://github.com/milesj/shapeshifter/blob/master/packages/parser-graphql/src/index.ts#L175

Are you using Film as a attribute value anywhere? I wonder if the implements is causing the problem.

konsumer commented 6 years ago

This is the generated schema from SWAPI.

It looks like it is used mostly at the top of the SDL, in output-type definitions:

type AddToFilmPlanetsPayload {
  filmsFilm: Film
  planetsPlanet: Planet
}

type AddToFilmSpeciesPayload {
  filmsFilm: Film
  speciesSpecies: Species
}

type AddToFilmStarshipsPayload {
  filmsFilm: Film
  starshipsStarship: Starship
}

type AddToFilmVehiclesPayload {
  filmsFilm: Film
  vehiclesVehicle: Vehicle
}

type AddToPeopleFilmPayload {
  charactersPerson: Person
  filmsFilm: Film
}
konsumer commented 6 years ago

Pardon, if this is review. A trick with interfaces is that even though they implement another type, they have to have all the fields defined that are in the interface, so it should be interchangeable with type. This means that Film must also have id: ID! defined. This Node thing is a convention from relay, that just means "these things can be uniquely identified by their id: ID!. In relay everything implements Node, but I've found it's a good idea, anyway, even if I'm not using a relay-client (apollo caching benefits from lookups on __type + id, for example)

konsumer commented 6 years ago

What is the required interface of the class GraphQLParser? I'm not really a typescript guy, but I can take a stab at rewriting using graphql/utilities, to see if it can deal with some of these messy things.

milesj commented 6 years ago

There isn't an interface to follow. All that's required is that the attributes are built correctly: https://github.com/milesj/shapeshifter/blob/master/packages/parser-graphql/src/index.ts#L278

The attributes need to match these definitions: https://github.com/milesj/shapeshifter/blob/master/packages/core/src/types.ts#L60

konsumer commented 6 years ago

I got a start to making schema definition, I think, in plain JS, but I don't have time to finish it right now, and it's missing a bit. I attached it, if you want to play with it. gentypes.js.zip

It outputs stuff like this from that SWAPI example:

{
    "name": "AddToFilmStarshipsPayload",
    "attributes": [
      {
        "id": "filmsFilm",
        "optional": true,
        "type": "shape",
        "reference": "Film"
      },
      {
        "id": "starshipsStarship",
        "optional": true,
        "type": "shape",
        "reference": "Starship"
      }
    ]
  }

I'm using graphql-tag just to quickly get a working normalized parser, but they in turn use graphql/language/parser.

konsumer commented 6 years ago

I think getType needs some work, the reference/scaler resolution stuff is pretty off. I can take another look after work.

milesj commented 6 years ago

I'm almost positive that Film should be a shape reference here: https://github.com/milesj/shapeshifter/blob/master/packages/parser-graphql/src/index.ts#L148

But why it's not being found is the question. Is Film used before it's defined?

Edit: Looks like it is, that's most likely the problem. I may need to do a double pass.

konsumer commented 6 years ago

I made this and it makes what seems like correct shapeshifter-schematic format, to me, but I'm still getting errors on the generated JSON.

I give up. I can just generate my own react proptypes with about the same amount of code, and don't really need to be concerned with this interim other schema, like the graphql type-system is fine for my purposes. I appreciate you taking the time to look at it.

milesj commented 6 years ago

No worries, good luck!