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

createRequest with transforms API #724

Closed
wants to merge 40 commits into from
Closed

createRequest with transforms API #724

wants to merge 40 commits into from

Conversation

mfix22
Copy link
Contributor

@mfix22 mfix22 commented Apr 9, 2018

@freiksenet I just recreated the createBatchOperation function using the new transforms schema, and

I am running into this error: "{ Error: Fields "bookingsByPropertyId" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional."

TODO:

  • More tests

Copy link
Contributor

@freiksenet freiksenet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff 👍

fragmentName => info.fragments[fragmentName],
),
info.operation.variableDefinitions,
export function createBatchOperation(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably name it createDocument. createDocument was never a public API and this probably should be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about createOperation? Since I think it's good to return the variables too.

},
transforms?: Array<Transform>,
): FetcherOperation {
const roots = Object.keys(rootDefs).map(key => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question here is whether we should auto-alias stuff or if we should expect user to alias themselves. I guess latter. Data-loading API can then alias by itself.

Copy link
Contributor Author

@mfix22 mfix22 Apr 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking users should add aliasing themselves:

{
  'user1:node': [{ id: 1 }, ...],
  'user2:node': [{ id: 2 }, ...]
}

But obviously with the API you specified below (:

transforms?: Array<Transform>,
): FetcherOperation {
const roots = Object.keys(rootDefs).map(key => {
const [args, info] = rootDefs[key];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this starts getting very complicated. How about this as a signature for rootdefs:

rootDefs: Array<{
  alias?: string,
  fieldName: string,
  args?: { [key: string]: any },
  info: DocumentInfo
}>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also extract it to a type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that works for me!

targetOperation: 'query' | 'mutation' | 'subscription',
rootDefs: { [key: string]: [{ [key: string]: any }, { [key: string]: any }] },
graphqlContext: { [key: string]: any },
documentInfo: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract this to a type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard that. Let's always pass info through rootDefs. Having two sources of truth is confusing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also you don't have fieldNodes in documentInfo atm.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kinda complicated. You might need to add fragment aliasing. But then we probably don't want to duplicate identical fragments. Same with variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah i always meant for that to be the full info object, but i just created a new type from the fields i was using. I'll update that 😄

CheckResultAndHandleErrors(info, options.fieldName),
transforms = [
...(transforms || []),
...roots.map(({ args }) => AddArgumentsAsVariables(targetSchema, args)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will reset a variable counter each time. I think you should have one AddArgumentsAsVariables, it should be modified accept args lists with fieldName or alias and assign variables to them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way we don't need to traverse AST that many times.

Copy link
Contributor Author

@mfix22 mfix22 Apr 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@freiksenet do you think that parameter's type should be:

args: { [key: string]: any } | Array<{ fieldName: string, alias?: string, args: { [key: string]: any } }>

?
That seems to be the only way we can support both patterns right?

transforms = [
...(transforms || []),
...roots.map(({ args }) => AddArgumentsAsVariables(targetSchema, args)),
FilterToSchema(targetSchema),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty damn proud this still works without any problem :D

targetOperation: 'query' | 'mutation' | 'subscription',
rootDefs: Array<OperationRootDefinition>,
graphqlContext: { [key: string]: any },
documentInfo: GraphQLResolveInfo,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this for now, but let me know if you want me to change this. documentInfo was a prop i though users could use to define properties that are global to that operation, and do not affect specific root fields. Like fragments, for example.

return {
query,
variables,
context: graphqlContext,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we return context: graphqlContext or context: { graphqlContext }? My original intention was the second because then you can take the return object and pass it directly to a fetcher.

Copy link
Contributor Author

@mfix22 mfix22 Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or should we remove context all together, and just have this function return { query, variables or { document, variables }?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just document and variables I think.

Copy link
Contributor

@freiksenet freiksenet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are nearly there.

  1. Can you add tests for createOperation? Test it by running execute with it. I at least want to see one that has aliases, one that doesn't, different arguments etc.
  2. Could you add API docs for createOperation to schema delegation docs?

return {
query,
variables,
context: graphqlContext,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just document and variables I think.

};
}

export default async function delegateToSchema(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pet peeve - could you move default export on top?

@freiksenet
Copy link
Contributor

As discussed, let's rename it to createRequest to match transforms API. Otherwise this is good. Once #527 is merged, we'll release that one as 3.0, merge this one and release it as @next pre-release for 3.1.

@freiksenet
Copy link
Contributor

Oh yeah, and you need to export it in src/index.ts.

@mfix22 mfix22 changed the title createBatchOperation with transforms API createRequest with transforms API Apr 18, 2018
@benjamn
Copy link
Contributor

benjamn commented Apr 23, 2018

@mfix22 Can you rebase this PR against master now that #527 has been merged?

@stubailo
Copy link
Contributor

@mfix22 so to recap, this is a way to do everything that delegateToSchema does except for actually sending the request, allowing you to do stuff like sending it in a batch?

Would this be better done via Apollo Link? Also, looks like there were some PRs around changing how subscriptions are done and similar, would you have a minute to update this if you think it's necessary?

@mfix22
Copy link
Contributor Author

mfix22 commented Jul 31, 2018

@stubailo yes. The PR takes a function that delegateToSchema uses, extends it to allow for multiple root values, and exposes that function. That allows are options like creating a batches request, and sending it directly to to a remote server without using execute.

I think it fits best here, considering 90% of the logic is just used directly by delegateToSchema.

@mfix22
Copy link
Contributor Author

mfix22 commented Aug 12, 2018

@stubailo do you need me to update anything here? 🙂

@gigouni
Copy link

gigouni commented Oct 8, 2018

Hi,

Is this still in the roadmap? It seems to be what I need to.

Thanks

ping @benjamn @freiksenet @mfix22

@mfix22 mfix22 requested a review from hwillson October 23, 2018 19:44
yaacovCR added a commit to yaacovCR/graphql-tools-fork that referenced this pull request Jan 16, 2020
…ethods.

May be useful for use with dataloaders or memoization.

See ardatan#724
yaacovCR added a commit to yaacovCR/graphql-tools-fork that referenced this pull request Jan 21, 2020
…ethods.

May be useful for use with dataloaders or memoization.

See ardatan#724
yaacovCR added a commit to yaacovCR/graphql-tools-fork that referenced this pull request Jan 21, 2020
…ethods.

May be useful for use with dataloaders or memoization.

See ardatan#724
yaacovCR added a commit to yaacovCR/graphql-tools-fork that referenced this pull request Feb 17, 2020
…ethods.

May be useful for use with dataloaders or memoization.

See ardatan#724
yaacovCR added a commit to yaacovCR/graphql-tools-fork that referenced this pull request Feb 27, 2020
…ethods.

May be useful for use with dataloaders or memoization.

See ardatan#724
yaacovCR added a commit to yaacovCR/graphql-tools-fork that referenced this pull request Mar 26, 2020
…ethods.

May be useful for use with dataloaders or memoization.

See ardatan#724
yaacovCR added a commit to yaacovCR/graphql-tools-fork that referenced this pull request Mar 26, 2020
…ethods.

May be useful for use with dataloaders or memoization.

See ardatan#724
@yaacovCR yaacovCR mentioned this pull request Mar 27, 2020
5 tasks
@yaacovCR
Copy link
Collaborator

Closing in favor of alternative implementation within #1307.

@yaacovCR yaacovCR closed this Mar 27, 2020
@yaacovCR yaacovCR mentioned this pull request Mar 27, 2020
22 tasks
@mfix22 mfix22 deleted the apollographql-next-api branch March 28, 2020 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants