How can a graphql subgraph forward query to another subgraph - proxy

There is a graphql api in a subgraph owned by another team
type Query {
user: UserInfo
}
Our team wants to create a new graphql api in our subgraph that return the same data type as a proxy.
type Query {
specialUser(encryptedUserId: ID): UserInfo
}
In our proxy, we will first decode the user id, then check if valid, then call the other team's api to get UserInfo, then do some modification to the result then return it.
Note the UserInfo object is very complicated, so we don't want to re-create resolver for each field.
I didn't find a way to extract the query then pass to the other team's api. We're using https://netflix.github.io/dgs/ and apollo in backend.

Related

Multiple field resolver resolves same rest API with different query parameters

We are planning to use graphql for orchestrations (For e.g. UI client invokes graphql service which goes to multiple rest endpoint and return the result). Problem here is from one rest endpoint we have to pass different types of query parameters based on the field requested by our client.
We use spring-boot-graphql and graphql-java-tools libraries to initialize graphql
type Query{
user(id: ID): User
}
type User{
phone: [Phone]
address: [Address]
}
type Phone{...}
type Address{...}
My code resolves user field and invoke rest endpoint to fetch phone and address information in a single call like
https:restservice.com\v1\user\123?fields=phone,address
How to resolve two fields expecting data from same rest service. I want something like when client request for phone then i needs to send fields in request parameters as phone alone without address. Can we do that? or is there any other way to define schema to solves this problem?
query {
user(userId : "xyz") {
name
age
weight
friends {
name
}
}
}
Knowing the field selection set can help make DataFetchers more efficient. For example in the above query imagine that the user field is backed by an SQL database system. The data fetcher could look ahead into the field selection set and use different queries because it knows the caller wants friend information as well as user information.
DataFetcher smartUserDF = new DataFetcher() {
#Override
public Object get(DataFetchingEnvironment env) {
String userId = env.getArgument("userId");
DataFetchingFieldSelectionSet selectionSet = env.getSelectionSet();
if (selectionSet.contains("user/*")) {
return getUserAndTheirFriends(userId);
} else {
return getUser(userId);
}
}
};
https://www.graphql-java.com/documentation/v12/fieldselection/

Graphql, nodejs, how to resolve non-root level query field based on if it is queried?

I'd like to resolve a field called 'outstandingBalance' in Client type. If front-end query:
query {
Client {
id
name
outstandingBalance
}
}
The resolver function for outstandingBalance is expensive to run. If front-end query:
query {
Client {
id
name
}
}
Then, don't trigger the resolver for 'outstandingBalance'. I have basic understanding of graphql and read most of its official document. But have not seen an answer to this pattern, or this way of using Graphql is not allowed?
Question
Is there a thing called "Nont-root level resolver" for graphql? like the 'outstandingBalance' field in Client type?
Question: How to implement in graphql? Especially using resolver:
async function outstandingBalance(obj, args, context, info) {
console.log('called...')
}
to query one field in one type based on if this field is queried?

How to Query fragments in a subtree of a top level query in a GraphQL server

Let's say a graphql server exists with the following schema:
query
-currentUser
--data1
--data2
...
Assume on your client, on page 1 of your app, you want data1 and page 2, you want data2. If I update data2 and want to refetch the query, do I need to query from the top level, resolving currentUser in order to get the updated data2? Is the only way around this by creating a root-level query for data2? E.g.:
query
-currentUser
--data1
--data2
-data2 (query on root of tree to avoid repeated currentUser calls)
Edit: I'm interested in how to do this using Apollo-client for React
The Relay top-level node query gives a standard way to do this. If most objects implement its Node interface, then you can use the top-level node(id: ID!) query to retrieve a specific object.
query GetFirstDatum {
currentUser {
id
data1
}
}
query GetSecondDatum($id: ID!) {
node(id: $id) {
... on User {
data2
}
}
}
This requires providing the Node interface in your IDL, having your objects implement it, and providing an implementation of the top-level node query that can return an object given its ID. Most server libraries have some level of support for this.

Retrieve requested GraphQL field without waiting for parent resolve using graphql-java-tools

I'm looking to optimise a GraphQL endpoint running on graphql-java and graphql-java-tools.
I have the following schema:
{
product(id: String) {
id
title
offer {
price
}
}
}
id and title come from service A, price comes from service B.
Right now, I have a GraphQLQueryResolver that returns a CompletableFuture<ProductResponse> where ProductResponse contains id and title, and I have another GraphQLResolver<ProductResponse> with a method offer(ProductResponse productResponse) that returns a CompletableFuture<OfferResponse>.
However, this means that I have to wait for service A to return a ProductResponse to begin to query service B for an OfferResponse. Both services only need the ID as input and thus could be executed in parallel.
Is there any way to execute both service calls in parallel without adjusting the schema?
In ProductFieldResolver, you need to return a CompletableFuture for id, CompletableFuture for name and CompletableFuture for Offers object. And inside each of the method implementation , call the dataloader of respective service. by that way it will be parallely executed.
I think you can consider using Apollo federation which solves it in a generic manner but still in an elegant way.
Try going through this - https://github.com/apollographql/federation-demo

Cache nested results

In my app, an user might request which friends did a specific action:
query($id: Int) {
post(id: $id) {
likes {
id
name
photo
}
}
}
But that means re-fetching the id, name and photo data for the same objects for different posts (since the server doesn't know what I already have cached). What strategy I could use to try leverage the cache here?
Only thing I can think of is in the query above I only request the id field and have separate queries for the name and photo and try to batch those.
There is no built-in way in GraphQL to share objects in the same result object graph returned. You have actually answered your own question. By normalizing the resultant graph of objects using IDs, it does reduce the amount of JSON you'd be transmitting back to the client. However, it requires the clients to request the data in a different way. For example,
query($id: Int) {
post(id: $id) {
likes {
id
}
}
likesByPostId(postId: $id) {
id
name
photo
}
}
In GraphQL, we let the clients make the decision on how to optimize the data fetching. The server simply returns the data in the shape the client requests. So you can't really decide for the clients.

Resources