Graphql Apollo Optimistic UI pattern - handle actual result? - graphql

We are following the optimistic ui pattern (http://dev.apollodata.com/react/optimistic-ui.html) with the apollo graphql client. Is there a way to handle the actual result from the server? For example, if the server did error on the mutation, we would like to notify the user. Is there a place to get the real result of the mutation?

The mutation returns a Promise. So you can handle the result from the server using than and catch.
If you are using the update functionality of the mutation definition you could use the catch to handle a server error. To get the error as object you could use errorResponse = JSON.parse(JSON.stringify(mutationError))

Related

Graph QL , can we put response layout in a file and use the same file while calling a GraphQL query?

With GraphQL is it possible to define response layout in a file and use the same file while calling the GraphQL query? just to avoid too long request body.
I tried to use different string for request and response from java code. For very large request and response its quite difficult to handle from source.

Is it possible to map a subscription parameter to an array at the mutation output?

I have a theoretical question. As I know subscription parameters must exist as a field in the returning type of the mutation. This means that the type of parameter must also match the type of the field in the returning object of the mutation. Am I right? Suppose I get an array with channels ids in the mutation response. I only send one channel id as a parameter in the subscription. Is it possible to map a subscription parameter to an array at the mutation output? If the channel id exists in the array (field channelsIds), the subscription must work. Is it possible to write this logic in the scheme itself, or is it technically impossible?
GraphQL schema:
schema {
mutation: Mutation
subscription: Subscription
}
type Mutation {
testMutation(input: TestMutationInput): TestMutationOutput
}
type TestMutationOutput {
channelsIds: [String!]!
userId: String!
userEmail: String
userPhoneNumber: String
}
type Subscription {
watchTestMutation(channelId: String!): TestMutationOutput
#aws_subscribe(mutations: ["testMutation"])
}
If I understand you correctly you want to filter based on if the mutation's returned value is in an array that is passed as an argument to the subscription. Sorry to say that is not possible at this time. Subscription filters only evaluate to true or false and cannot accommodate any logic other than that.
At the end of October 2020, I contacted AWS support for advice on this issue. I think this answer may be useful to someone, so I post their answer.
Please allow me to inform you that the use-case that you have
mentioned in the case is currently not possible via AppSync. I
understand that the lack of the feature may be causing inconvenience.
There is an internal feature request already with the AppSync team to
incorporate this feature and I have added a +1 on your behalf. It is
worth noting, that once this feature request is with the team, it will
be up to the team as to if/when this potential infrastructure feature
is implemented, and because of the limited visibility into the
progress of internal development processes, I won’t be able to provide
an ETA regarding its release. I would request you to keep an eye on
the what's new page or the AWS Blogs as all new feature requests and
enhancements are posted there[1-3].
However we can suggest a couple of workarounds in this case:
Filter the required fields on client side itself after receiving the values on the client-side from AppSync.
If the values to be filtered are very limited we can use a fake mutation made with the help of a resolver mapped to “None” Data
source. In this flow, we would create a lambda function that uses a
DynamoDB stream as the trigger. The Lambda function is triggered
whenever there's an update to the DynamoDB table.

We can then include logic in the Lambda function to filter the
required fields and perform a mutation to AppSync. In AppSync, the
mutation which was called by lambda would configured using a resolver
mapped to a “None” Data source. The None data source type passes the
request mapping template directly to the response mapping template.
And when we subscribe to this mutation, we will directly get the
filtered data from Lambda that was used to call this mutation. Please
refer to [4] for a step-by-step description of this process.
But please note that this workaround is cumbersome and would require a lot of changes if the required field values keep changing. Workaround 1(handling it on the client-side) is usually the preferred way to handle this use-case.
Resources:
[1] https://blogs.amazon.com/
[2] https://aws.amazon.com/new/
[3] https://aws.amazon.com/releasenotes/
[4] https://aws.amazon.com/premiumsupport/knowledge-center/appsync-notify-subscribers-real-time/

How do I generate fragment types for apollo client?

I have an app written with reason-react using apollo-client. I have defined some fragments on the frontend to basically reuse some field definitions. I'm setting up automated tests for a components that uses fragments, but I keep getting this warning saying I need to use the IntrospectionFragmentMatcher.
'You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types. Apollo Client will not be able to accurately map fragments. To make this error go away, use the `IntrospectionFragmentMatcher` as described in the docs: https://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher'
I've tried setting up the fragment matcher according to the docs. The codegen result returns no types:
{
"__schema": {
"types": []
}
}
When I queried my server and looked at the manual method recommended by apollo-client, I noticed it would also return no types.
Another strange thing is that when I don't use the fragment matcher, I get the mocked response back but I just get the warnings from apollo. If I do use it then the mocked response doesn't return correctly.
Why would I query the graphql api for fragments defined in my frontend code? Why would I only received these errors when running the tests & using mock data, but not when running my actual application?
As the error states, the default fragment matcher does not work on intersection or union types. You will need to use Apollo's IntrospectionFragmentMatcher. It works by asking the server (introspecting) for information about your schema types, and then providing that information for reference to the cache so that it can match the fields accurately. It's not querying the server for information about the fragments you are defining on the front end, it's asking for data about the GraphQL schema that must be defined on your back end so that it can properly relate the two. There is an example in the documentation, also more information here.
As for why your server is not returning any types, that is a separate issue that would require more info to debug. If you're using Apollo Server, doublecheck your schema to make sure all the necessary types are defined properly and that you are passing them into the server when it's initialized.

How to use a Apollo GraphQL query result as the input of another one? Aka: request chaining

I know this has been asked a couple of times before, but I have found no definitive solution to whether this is possible with GraphQL. And I have a strong feeling this should be possible as it should be relatively easy to implement due to GraphQL queries running sequentially in Apollo.
I have a situation where I'm doing a GraphQL mutation first on the client, and then immediately after doing a query which uses the results from the previous query. This causes a needlessly long response time waiting for the server to respond to both requests. The requests look like this:
mutation createWebSession($authId: ID!) {
webSession: createWebSession(authId: $authId) {
token
userId
}
}
query listUserPaymentMethods($userId: ID!) {
userPaymentMethods: paymentMethods(userId: $userId) {
id
}
}
I know that one simple band-aid solution to avoid making 2 round trips to the server is creating a new single GraphQL mutation endpoint that does both services on the back end. But that seems to defeat the purpose of writing modular, reusable GraphQL endpoints. As such, I'm curious if someone knows if Apollo GraphQL supports a cleaner way to chain 2 requests in which the results from the previous one are available to the next one as inputs.
Any help would be greatly appreciated, thanks.
This is a limitation that specific to GraphQL in general. There is no way to do this in a single request for a couple of reasons:
While a GraphQL document may include any number of operations, only a single operation will be executed. If a document includes multiple operations, all operations must be named and the request must include an operationName parameter that specifies which operation to execute. In other words, while you can combine multiple queries into a single operation, or multiple mutations into a single operation, you cannot cannot mix-and-match queries and mutations.
Given any two fields that share the same "parent" field, both fields will resolve at the same time. The only exception to this are root level mutation fields, which do resolve in sequence. As such, GraphQL does not support any syntax that would let you reference another field and use it as the input to some argument.
One possible workaround is to include a field in your createWebSession payload type whose field is the Query type. I illustrate this approach in this article as a means of refetching queries but it would work for what you're trying to do as well.

Run Apollo query only on React component mount (without queryData and lifecycle)

I'm using Apollo extensively in a fairly big React app I'm building, and I've found myself facing the same limitation several times.
I want to perform a query only on component mount, so that a change of this component sub-route will no re-trigger the query. I also really want to keep the container pattern, where I declare my query in the container, wrap my component and forget about it, so that my component itself remains clean of any Apollo stuff.
So far, I've been able to do that by making my own Apollo high-order component that takes a component, a query and its options and returns a new component that will automatically run queryData on componentDidMount. Here's the code. I then use it this way: apolloQueryHOC(MyComponent, queryOptions);
But on a new component I've started implementing paging, and this approach simply doesn't work/becomes way too ugly for the complex paging logic I've implemented. The thing is, it works like a charm when I use the basic Apollo container approach. But it runs on every route/prop change.
So my question is, is there a way to run a "container" query only on mount, other than using withApollo and such?
Ah, the problem was actually that I was handling auth in a middleware, so my query had '' as token, and the token was fetched from indexedDB and added to the query in the middleware, overriding ''.
So the query result stored in Apollo store (with the proper token as a param) was never matching the query with '' as token, resulting in Apollo querying again and again from the server.

Resources