gramps-graphql / gramps--legacy

The core data source combination engine of GrAMPS.

Home Page:https://gramps.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question about handling actions on a per-request basis

timrs2998 opened this issue · comments

We've been struggling with how to do things on a "per request" basis. For example, we want to have a child logger created per request, forward headers found in a request, or setup a dataloader that is created for every request.

We're still on the old GrAMPS, not on 1.0 yet, but have always found performing these actions with GrAMPS to be awkward.

  • logging: we create logger in middleware piece, but need "hacks" to get to the logger in formatError or to swap the logger used in the base connector. I'd really like to create another child logger for each data-source with the context name.
  • header forwarding: pass context.req.headers from resolver, through model, to the connector to pass headers through request-promise
  • dataloader: hackery black magic

Do you have any insights into these use cases especially around forwarding headers and constructing dataloaders? It's been doable through hacks, but I'm wondering if the newer GrAMPS 1.0 makes these tasks any easier (less hacky).

Anything that needs to be done "per-request" should be done within context

In 1.0 a data-source provides either an Object to use as context or a function that returns an Object. The req is provided to this function as its first argument.

const userloader = new DataLoader(...);

export const context = req => ({
  headers: req.headers,
  userloader,
});

These are then used in resolvers.

export const resolvers = {
  Query: {
    currentUser: (root, args, context) => context.userloader(context.headers.userId)
  }
};

So looking at a data-source, https://github.com/gramps-graphql/data-source-xkcd/blob/master/src/index.js#L13 you're saying that this context can be either a function or an object. I see the support for that in https://github.com/gramps-graphql/gramps/blob/master/src/gramps.js#L142 now.

That actually helps a lot, thanks!

@timrs2998 Also, I extracted the REST helpers (the model and connector) into a new package at https://github.com/gramps-graphql/rest-helpers — we can tackle the DataLoader issue there, because it should be creating a new instance per-request.

@ecwyne is correct about the header forwarding, but you can also do this from the gramps() call instead of on a per-data source basis if you drop it into the extraContext prop.

const GraphQLOptions = gramps({
  dataSources: [/* ... */],
  extraContext: req => ({
    headers: req.headers,
  }),
});