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

Support query batching #192

Open
danwkennedy opened this issue Dec 7, 2017 · 29 comments
Open

Support query batching #192

danwkennedy opened this issue Dec 7, 2017 · 29 comments
Labels
enhancement Issues outlining new things we want to do or things that will make our lives as devs easier

Comments

@danwkennedy
Copy link

We've come across a situation where query (and mutation) batching would be very useful. I noticed that this was an issue in the Android project but not in the iOS one so I wanted to add a reference here.

apollographql/apollo-kotlin#513

@martijnwalraven
Copy link
Contributor

Thanks! Once #186 lands that should make it easier to add support for query batching.

Out of curiosity, what is your use case? Especially with HTTP/2, query batching doesn't seem to have that many performance benefits and may actually degrade performance.

@danwkennedy
Copy link
Author

We'd like to use it to pass n-mutations in a set order. Our specific use case is the removal of n items in a hierarchical list (where you can't remove the parent before the children are removed) in one go. An example for a mutation like this could be:

mutation {
  child1: remove(id: "2"){ id }
  child2: remove(id: "3"){ id }
  child3: remove(id: "4"){ id }
  parent: remove(id: "1"){ id }
}

We didn't want to go the route of having the removal of the parent take the children so we can catch potentially erroneous behavior and ask the user what they want to do (i.e. move the children to another parent, or actually remove all the children).

@martijnwalraven
Copy link
Contributor

Ah, I see. Query batching as currently implemented in Apollo Server would work for this I think, but ordering isn't actually guaranteed (unlike putting multiple mutations in a single operation, as you've done above).

Would something like remove(id: ..., cascadeToChildren: true) or a batch removeAll(ids: ) be an alternative?

@danwkennedy
Copy link
Author

I was considering the removeAll(ids: [ID]!) route. The only downside is we lose the nice error tracing that GraphQL gives us. i.e. If ID number 3 fails, then the multiple mutations in a single operation would give us a trace to that failed mutation and the client would know to deal with just that failed mutation. With removeAll, a custom error format would be required to give us that kind of functionality.

I also think I might not quite understand how query batching works in Apollo Server. Does the batching simply let you send multiple operations in a row? If that's the case then you're right it's probably not what I'm looking for. Instead what I was describing is a sort of mutateInSequence method that takes a list of mutations and merges them into that un-named operation and runs that. It'd be really cool but also sounds nasty to implement 😄

@martijnwalraven
Copy link
Contributor

Depending on the underlying service or datastore, a single mutation would have the benefit that you can run it in a transaction and have everything automatically rolled back when a removal fails. But you're right, there is no built-in way to include an error per id. Perhaps you could define a custom result object if you really need it. Something like:

removeAll(ids: $ids) {
  removedItems {
    id
  }
}

Query batching in Apollo Server is indeed just a way to send multiple operations in one request. Currently operations are executed in sequence I believe, but it is not guaranteed and we may want to execute them in parallel.

@nuke-dash
Copy link

Hi @martijnwalraven, are there any plans on adding support for Transport-level query batching?
Our app can do multiple queries at once and then it would be useful if those could be send to the server in 1 request instead of multiple request.

@thonydam
Copy link

Hey guys,

Do we have any plans on supporting query batching? Is there a doc we can refer to about the roadmap of Apollo-iOS?

@designatednerd designatednerd added the enhancement Issues outlining new things we want to do or things that will make our lives as devs easier label Jul 11, 2019
@designatednerd
Copy link
Contributor

Marking this as an enhancement - I don't have a timeline for this but it does seem like a useful thing to add support for to reduce the number of round-trips necessary if possible.

@thonydam Right now we don't have a roadmap doc, but I'll be working on that at some point in the next few months once I get the open issues a bit more under control.

@thonydam
Copy link

@designatednerd Thanks for the update and your work! Glad to see that this repo will get more love!

@cezarsignori
Copy link

Any updates on this topic?
(This topic is mixed with another and followed up on #884. Not sure what the current status is though).

@designatednerd
Copy link
Contributor

I'm going to look at adding both of these as we update the networking stack but I do not have an ETA.

@benjaminsaurusrex
Copy link

@designatednerd - can this issue be re-examined for viability following the network stack rearchitecture?

@daniel-r-hartman
Copy link

Has there been any update to enable query batching for iOS? My team is hoping to use batching for web and android requests but we're not sure this is the right path since it isn't currently supported for apollo client in iOS.

@danwkennedy
@designatednerd
@martijnwalraven

@calvincestari
Copy link
Member

Hi @daniel-r-hartman - Our team won't be able to get to this until v2.0 where networking will be the focus of that major version. We are always happy to work with community member contributions though; reviewing and guiding where we can.

@daniel-r-hartman
Copy link

Thanks for the reply @calvincestari. Is there any timeline or estimate of when this feature might be available?

My team is currently evaluating working on a custom solution for batching, vs contributing to this project, vs non-batching solutions.

@calvincestari
Copy link
Member

There is no estimated timeline for v2.0 yet. We're still working on v1.0 which is focussed on code generation. If I were to guess at a timeline right now I'd say second half of 2022.

@tspike
Copy link

tspike commented May 9, 2023

Assume this is still pending? Thanks!

@calvincestari
Copy link
Member

Assume this is still pending? Thanks!

We haven't started on 2.0 yet. This will be included in that work.

@ArunVicky001
Copy link

I am currently using apollo client 1.2.0 ios version, but query batching is not available though. Could you please update on this

@calvincestari
Copy link
Member

calvincestari commented Jun 22, 2023

Hi @ArunVicky001. Query batching is still not a native feature of Apollo iOS but it is possible and you will need to code your own request body creator to get it working.

0.51.1 included a change to expose the request body creation. This is the hook for you to use and build a custom request body that would batch together the operations. You'll also probably need a custom response interceptor to parse the response if it's going to include more than a single data object in the body.

@ArunVicky001
Copy link

@calvincestari which means we need to make change in the query itself right?

@calvincestari
Copy link
Member

You need to change the request that gets sent to the server. You cannot change the GraphQL query to enable batching.

@ArunVicky001
Copy link

Got it,

on other hand can we implement like this?

import Apollo

let apolloClient = ApolloClient(url: URL(string: "https://api.graphql.org/")!)

let query1 = """
query {
  viewer {
    name
  }
}
"""

let query2 = """
query {
  repository(owner: "apollographql", name: "apollo-client") {
    name
  }
}
"""

let dispatchGroup = DispatchGroup()

var viewerName: String?
var repositoryName: String?

dispatchGroup.enter()
apolloClient.fetch(query: query1) { result in
  defer { dispatchGroup.leave() }
  
  switch result {
  case .success(let graphQLResult):
    viewerName = graphQLResult.data?.viewer?.name
  case .failure(let error):
    print("Error querying viewer: \(error)")
  }
}

dispatchGroup.enter()
apolloClient.fetch(query: query2) { result in
  defer { dispatchGroup.leave() }
  
  switch result {
  case .success(let graphQLResult):
    repositoryName = graphQLResult.data?.repository?.name
  case .failure(let error):
    print("Error querying repository: \(error)")
  }
}

dispatchGroup.notify(queue: .main) {
  if let name = viewerName {
    print("Viewer Name: \(name)")
  }
  if let repoName = repositoryName {
    print("Repository Name: \(repoName)")
  }
}

@calvincestari
Copy link
Member

Yes, you could do that. It's slightly more complicated for the client but the end result of time-to-wait for the user should be the same as query batching on the server because the server wouldn't combine the responses, i.e.: the client would still have to parse two data responses.

The best eventual solution for this is probably to use @defer. We're working on it now for Apollo iOS but it would also require changes to your queries to combine the fields you want immediately and the ones that can be deferred.

@calvincestari
Copy link
Member

@ArunVicky001 I'm going to close this issue now as there isn't anything actionable for our team.

@calvincestari
Copy link
Member

Oh wait, this is a long-standing issue we're keeping around for the 2.0 work. My mistake.

@calvincestari calvincestari reopened this Jun 28, 2023
@ArunVicky001
Copy link

What is the update? Any luck for query batching

@BobaFetters
Copy link
Member

@ArunVicky001 This work is going to be included in the work for version 2.0 which doesn't currently have a date however you can follow our roadmap which is updated consistently to keep track of upcoming and planned work.

@ArunVicky001
Copy link

@BobaFetters Thanks for your response..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Issues outlining new things we want to do or things that will make our lives as devs easier
Projects
None yet
Development

No branches or pull requests