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

Dynamically adding mutations #314

Closed
MarkAndrewJohnson opened this issue Mar 16, 2016 · 9 comments
Closed

Dynamically adding mutations #314

MarkAndrewJohnson opened this issue Mar 16, 2016 · 9 comments

Comments

@MarkAndrewJohnson
Copy link

To make a modular system we want to add mutations dynamically after creating the core schema object. For example in a subsequently loaded file graphql.user.js (graphql.organisation.js, and so on) to add user operations (mutations and queries).

I can't seem to find a way to add mutations in this manner that doesn't break graphiql in one way or another. Is there a recommended way for a modular schema implementation?

Documentation would certainly help with this scenario.

@freiksenet
Copy link
Contributor

You can defer the actual creation of schema to later steps. So instead of first creating schema and then adding more stuff to it, you collect all the parts first and then create one big schema for them.

@MarkAndrewJohnson
Copy link
Author

So essentially if I have, say, 10 modules each with 10 mutations (ignore queries for now), I would have to define each of those in each module file, export them, and then include all 100 of them explicitly when building the schema? That seems rather messy and unmodular.

Rather, I was hoping I could do something like

module.exports = function(schema) {
  schema.getMutations().addMutation({
    myMutation: new GraphQLObjectType({ ... })
  })
}

or addMutations taking in an array of mutations like:

schema.getMutations().addMutations([
{ ... },
{ ... }
])

This would make it cleaner to pass the generic schema to module definition files and add module specific queries and mutations, and make each module easier to manage independently.

@skevy
Copy link
Contributor

skevy commented Mar 16, 2016

@MarkAndrewJohnson it seems like you may not be using es6 modules...but if you were you could do something like:

export const myMutation = ...

and then when you put your schema together:

import * as mutations from './mutations'

and then use the resulting imported value to put your schema together.

....

In general though I get your point :) Just offering an alternative.

@MarkAndrewJohnson
Copy link
Author

Thanks for that. Just what we're trying to avoid but obviously not much choice at the moment. Being able to wrap each of a module's own mutations and queries in a self contained module file would be a great option to see in future.

@freiksenet
Copy link
Contributor

You will still have to import all the modules that you want to extend your mutations from if you want to use them. Regardless of the way you add the mutations, the file will only be loaded if it's imported somewhere, so I really don't see how it's more modular.

@MarkAndrewJohnson
Copy link
Author

@freiksenet except if you were to do something like require('myModel')(schema) which in turns calls .addMutations(...), .addQueries(...) or similar functions in which case you don't have to import anything at all.

@freiksenet
Copy link
Contributor

Well you do import 'myModel' here :)

What's wrong with:

const schemaCreator = new SchemaCreator();
require('myModel')(schemaCreator)
const schema = schemaCreator.getSchema();

@leebyron
Copy link
Contributor

leebyron commented Apr 6, 2016

We intentionally never edit a schema after it's been created (we consider it immutable). Doing so ensures that we can use an instance of GraphQLSchema as a key for memoization amongst other things. We also validate a schema when it's created, which would be much more difficult to do if we needed to do that across many edits.

The way to add mutations (or anything else for that matter) defined in other modules is to simply import them for use:

import { modularMutationsA } from './modularMutationsA';
import { modularMutationsB } from './modularMutationsB';

const schema = new GraphQLSchema({
  query: { ... },
  mutation: new GraphQLObject({
    name: 'Mutations',
    fields: {
      ...modularMutationsA,
      ...modularMutationsB
    }
  })
})

Where each modular mutations export their relevant mutation fields:

// modularMutationsA.js

export const modularMutationsA = {
  mutationA: {
    type: SomeType,
    resolve() {
      // go write some stuff!
    }
  }
};

There are plenty of forms this could take, depending on how you want to organize your files. For example, perhaps you want to define your mutations in a separate file:

// mutations.js
import { modularMutationsA } from './modularMutationsA';
import { modularMutationsB } from './modularMutationsB';

export const MutationType = new GraphQLObject({
  name: 'Mutations',
  fields: {
    ...modularMutationsA,
    ...modularMutationsB
  }
});
// schema.js
import { MutationType } from './mutations';

const schema = new GraphQLSchema({
  query: { ... },
  mutation: MutationType
})

@leebyron
Copy link
Contributor

leebyron commented Apr 6, 2016

I think @freiksenet's suggestion is also a good one if you really want to edit as you go instead of compose (even though I personally prefer the latter).

The builder pattern is a good way to make immutable things. You could do something like:

class SchemaBuilder {
  // any API you care about adding.

  getSchema() {
    return new GraphQLSchema({
      // compose with everything that's been built so far.
    })
  }
}

then you could use this like:

const builder = new SchemaBuilder();
// do whatever you want with builder, including passing it to other functions
const schema = builder.getSchema();
// now you've got your schema ready to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants