graphile / crystal

๐Ÿ”ฎ Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!
https://graphile.org/
Other
12.61k stars 571 forks source link

Expose hooks to enable extending the GraphQL schema #300

Closed cellis closed 7 years ago

cellis commented 7 years ago

Let's say I have a query and I need to call out to some api (either internal or external) to fulfill it? What's the best way to accomplish this? Does postgraphql expose resolve hooks? For some things, obviously I can precompute the data by saving it to postgres, but i can forsee problems where it wouldn't work.

benjie commented 7 years ago

We don't currently support doing that through postgraphql, though if you understand the caveats you could try doing it through postgresql directly using foreign data wrappers. Definitely something that we have in mind through.

idibidiart commented 7 years ago

Very new to GraphQL so this may not make sense but I assume in all these types of SQL-to-GraphQL-Schema solutions that we get an actual GraphL schema generated statically and as such we should be able to extend that schema with new types and resolvers etc. Or does postgraphql implement its own graphql server that consumes the database schema directly and will ignore or throw in case the graphql schema does not map 1:1 to the db schema?

danvk commented 7 years ago

It would be great to have some hooks which make this possible. It's the difference between postgraphql being an all-or-nothing solution and one which can fit into a larger system.

@zamiang and my use case: we have a database which contains our own data as well as user IDs from an external service which exposes a REST API. We'd like to expose a unified GraphQL API over both services. To fill in data from the external REST API, we'd need to issue a second request after the Postgres result comes back.

I imagine defining the GraphQL schema for something like this would be tricky. @benjie any thoughts on a good workaround for this now? We're thinking about having two independent GraphQL endpoints: one for our own data with PostGraphQL and another which wraps the external REST API. Not ideal and not very GraphQLy, but it will let us keep moving.

benjie commented 7 years ago

I'm afraid I can't give any solid advice on that; I've just added a couple tiny REST APIs where necessary for my requirements. You might try reading up on merging GraphQL APIs (I've no idea if this will be successful or not):

https://www.google.co.uk/search?q=combine+graphql+schemas&oq=combine+graphql+schemas

https://gist.github.com/icebob/553c1f9f1a9478d828bcb7a08d06790a

https://gist.github.com/voodooattack/b0484625a90191a4dde4aabae8884243

cellis commented 7 years ago

I've written about this at https://medium.com/@awesboss/the-ultimate-graphql-solution-af3a8afbf85#.vm9c0w6kr. So, here's my advice for postgraphql users: you'll need to use a different library to write your API stuff, ideally graphql compose. For the custom API stuff see here: https://github.com/nodkz/graphql-compose/issues/32. Then, if you're using relay you'll need to use a custom network layer that knows how to send queries to both postgraphql and graphql-compose.

On Feb 27, 2017, at 10:17, Benjie Gillam notifications@github.com wrote:

I'm afraid I can't give any solid advice on that; I've just added a couple tiny REST APIs where necessary for my requirements. You might try reading up on merging GraphQL APIs (I've no idea if this will be successful or not):

https://www.google.co.uk/search?q=combine+graphql+schemas&oq=combine+graphql+schemas

https://gist.github.com/icebob/553c1f9f1a9478d828bcb7a08d06790a

https://gist.github.com/voodooattack/b0484625a90191a4dde4aabae8884243

โ€” You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

calebmer commented 7 years ago

So we do have hooks internally to extend the schema. Itโ€™s actually how we implement procedures ๐Ÿ˜Š. See: https://github.com/calebmer/postgraphql/blob/61fe4550751aa45c07783a6ae17fdcd01b73f956/src/postgraphql/schema/createPostGraphQLSchema.ts#L124-L139

I think a very good first step towards this goal would be exposing these hooks experimentally to everyone! We can move from there as people start extending their schemas and find out what we need. We can introduce these hooks under an experimental_hooks property (Iโ€™m taking the _ convention from React ๐Ÿ˜‰). We can document these hooks but with the warning that we reserve the right to make breaking changes in non-major releases until they are stabilized. What do you think about that?

To expose these hooks would actually be pretty simple, so if anyone wants to open a PR, letโ€™s discuss!

cellis commented 7 years ago

@calebmer As it stands, the lack of hooks is the only thing preventing quite a few people using this library. Exposing them and then deprecating in the next version would be much better than not. Perhaps I will open a PR, but no promises, as I've already signed up to do quite a few other graphql libraries ;).

benjie commented 7 years ago

๐Ÿ‘

mikeburgh commented 7 years ago

I have spent some time getting custom mutations working.. following the advice of @calebmer I used the _hooks and added a new one for custom mutations.. which is picked up in createMutationGqlType and added to the mutation for GraphQLObjectType.

What are the thoughts on storing the mutations and then injecting them.. currently I am thinking about adding a config/CLI option to pass in a path, and the files in that path would be imported and added ?

Each file would be required to export a GraphQL schema object, something along the lines of:

{"testMutation": {
            args: {
                input: {
                    description:'the input'
                    ,type: new graphql.GraphQLNonNull(graphql.GraphQLString)
                }
            }
            ,description:"test Mutation injection"
            ,resolve: function(_source,args, context, info) {
                 return  {i:args.input,t:'re'};
            }
            ,type: new GraphQLObjectType({
                name: "testPayload"
                ,description: "The output of our  mutation."
                ,fields: {
                    i: { type: graphql.GraphQLString, description: 'Something out' },
                    t: { type: graphql.GraphQLString, description: 'Something else out' },
                }
                }
            )
        }
}

My TypeScript knowledge is 0, so for now I have done this with the compiled JS code.. so I still need to port it back into TypeScript and submit a PR.. pending the feedback.

The other aspect I want to solve is hooking into a mutation that is created by PostgrapQL prior to it being returned to the client (for post processing work etc).

benjie commented 7 years ago

v4 adds a plugin architecture to the generated schema