When using GraphQL federated resolvers to resolve an array, and one of the resolved items cannot be found:
Observed behaviour: null data returned for entire query, no error message.
Desired behaviour: the item which cannot be resolved is silently dropped from results array.
What works
Using Apollo Server federation, we are successfully able to resolve the following query:
query {
products {
name
reviews {
id
score
}
}
}
where products comes from the Product subgraph and score is resolved by the Review subgraph.
This works fine when all the review ids passed to the Review subgraph are resolvable.
Our Problem
Sometimes the Review subgraph deems that a review should not be returned. The business case could be, for example, it was automatically marked as spam and is blocked until a manual check is done.
In this situation, the Review subgraph returns null for this ID. Example query:
query {
_entities(representations: [
{id: 1, __typename: "Review"},
{id: 2, __typename: "Review"}
]) {
...on Review {
id
score
}
}
}
Result
{
"data": {
"_entities": [
{
"id": "1",
"score": "94"
},
null
]
}
}
When this happens, we would want the federated results to contain the Product and only review 1, the non-resolveable review id 2 having been dropped from the array. Like this:
{
"data": {
"products": {
"name": "Phone cover",
"reviews": [
{
"id": "1",
"score": "94"
}
]
}
}
}
However, Apollo Server returns null for the entire query, with no error message:
{
"data": null
}
Is this expected behaviour? Is there any way to gain the result I want, or otherwise control how Apollo reacts when one item in a reference array is not resolved?
Related
I'm very new to GraphQL, and i'm trying to perform some example queries to this graph. In particular i'm trying the User schema.
According to that documentation, the schema is the following:
id: ID!
liquidityPositions: [LiquidityPosition!]
usdSwapped: BigDecimal!
And here is query i tried:
{
user (where: {id: "0x7c9C48b7cBEbBDA3268435F20c81f15A538C566C"}) {
id
liquidityPositions
usdSwapped
}
}
This query fails, i keep getting the following response:
{
"errors": [
{
"locations": [
{
"line": 0,
"column": 0
}
],
"message": "No value provided for required argument: `id`"
}
]
}
How can i provide the id field and where am i supposed to provide it? Thanks in advance!
You've got a couple of problems with that query. First, to get a user by id, remove the "where" and curly braces from your query. Secondly, the liquityPositions field needs a selection of subfields. Like so:
{
user (id: "0x7c9C48b7cBEbBDA3268435F20c81f15A538C566C") {
id
liquidityPositions {
id
}
usdSwapped
}
}
That website you linked to will show you errors with your query so you can interactively learn more about what is supported.
I would also suggest running through the introduction to GraphQL here: https://graphql.org/learn/ to get a handle on how things are done.
I am working with a sample of graphql query which I want to further bind to a FlatList object in a React-Native app. But I am still struggling to understand what I should pass on then nextToken parameter in order to get a slice of objects destined to a second page...
Tried to pass the next or last id or index, but it didn't work - it asks me to provide a valid nextToken, which I don't know what kind of data it is.
I'm running through AppSynch console.
My query:
query ListResources(
$nextTokenPlants: String = "Orange Tree"
$limitPlants: Int = 3
) {
listResources {
items {
id
name
Plants(limit: $limitPlants, nextToken:$nextTokenPlants) {
items {
id
name
filterName
description
bath
tea
insence
children
}
nextToken
}
}
nextToken
}
}
This is the result I get:
{
"data": {
"listResources": {
"items": [
{
"id": "361dee16-d567-41ed-b1d4-9baa4a7ffdcc",
"name": "Plantas",
"Plants": null
}
],
"nextToken": null
}
},
"errors": [
{
"path": [
"listResources",
"items",
0,
"Plants"
],
"data": null,
"errorType": "DynamoDB:UserIllegalArgumentException",
"errorInfo": null,
"locations": [
{
"line": 9,
"column": 7,
"sourceName": null
}
],
"message": "com.amazonaws.deepdish.common.pagination.InvalidPaginationTokenException: Invalid pagination token given."
}
]
}
I expected to get a list of 3 of the itens stored on "Plants", starting from the "Orange Tree" onwards... Could anyone pls shed some light on it?
nextToken is a String that you get in the response when you send a request, looks like
eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGdtYVZObHlaR3FSa3hDRnFVWWdFeEZDM0FMY1JRdE9UOEt2dWFLMExzcjJ3RlBPMGdpcC96bjQ5VjFOVElKUng1M0FBQUNlVENDQW5VR0NTcUdTSWIzRFFFSEJxQ0NBbVl3Z2dKaUFnRUFNSUlDV3dZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF4VEt5Myt3RUJuSzVSU2hsUUNBUkNBZ2dJc1lmdDk2WVVmQ053Tms2WGkxc3Z2bUgzSGFQZTdNTm1DQWhDcWJ5RFlydXZwTmR6WUNBQ0pJS1RZQlVWdk1xbU9EV2s2SVdLTzlqNmRhenNWZGZYTmFTQmxseE9yUS9BZWY0c2NpL1duWVUweWEyNCthZGQxcVNaMGZEWDZUdkJDak1XQjQ4QmhTQmxLejk2TFpiZ3pDN3dJTzVPRStFbUxHdVhRcURXcUpNZDM3Rm0yNUdiQVU1Tlg1YWVtWE1PbnVKSkZpTzA3U3ZhdUVZMWZwaXZCVU9pMHlxTVlIYk5PMkQ4aDZRVmQ4eW4yTXl3YU9UUHYwWFJZNitrakgvNGlyOWtrdlVXK1pvNFdOeDFBL2h1MlF4Z0lSczQ3d0xTT2NsaXk1Y3o0eFFzM2xqREhYL3M0TTVwT2phTCt0TGpYOUlWcGZCVW45bUgwWEw4ZEFkR0VZRGdjeWpMUHlPdWFnREVNMWR4M09neTg4NGJPclJ3VVgrRmM0UHpGekRqSHZjcjBGSVVXNEM2ZUxzYVRtRjNFakhLRk9ERllDWWkrQ01QNFg0a0dCdTFJQ3BLQjNJdEx2VTZHcUxNVDRMd3NJbkk4SVBhZm1MRnYxRTZDbWxxMnFKZ2wxY1BEVmR6MVFDc0Ezby9vR0VHUkI2VkJtc3VFSUFuOW10OVJzaWpyaklqUm5DQzlSWHA3NnA0WlhWanBJY0dSVU9GTktvZGNnMVpNbGV0a200clhBUGJacFZ5TDdkcnQyTXlEVERQd1crcjZsRHJUUVJJZzI4MEl3Y3ZkQzB1RWRrb0hqTlZPR0kwSWxsSnZ5RjRWTCtNNzRuWXcwNVNSWllJODdGcGdzR21LZjRvWVA1VG9temRVUUR0YWkrZVRJcUxGRjlGYzk0UUNwZlYrVlpmeVU0Mk4yTnRtNi9MYUhrZ08zdGRTUHN1bGhQWVRuMGRQNU5aWG5pODU1eGZyL1N2dDQ2VU0xb3I2UEE9PSJ9
and it has nothing to do with your table keys.
Let me explain now how does it work:
When you send the request for the first time, you don't send nextToken since you don't have it and then you get the first portion of your data.
When you receive that first portion, if there exist more data, you get nextToken in the response.
Now, you have nextToken, you send another request to get the 2nd portion of your data. You should send that token in the request, so your backend knows from where to start.
You get your 2nd portion of data and a new nextToken if there is still some data to fetch (then you need to repeat step 2) or null in nextToken if there is no more data.
I hope that it's clear now
I was looking at the new graphql endpoint exposed by Magento 2.3.1 and above at the query for listing products:
query products(
pageSize:6,
currentPage:1,
filter:{
category_id: { eq: "3" }
}
) {
filters {
name
request_var
filter_items_count
filter_items {
label value_string
}
}
items {
id
name
small_image {
url
}
# ...
}
# ...
}
The response body yields products in the items property just as expected and a bunch of custom filters in an array in the filters property which look like this:
"filters": [
{
"name": "Activity",
"request_var": "activity",
"filter_items_count": 12,
"filter_items": [
{
"label": "Outdoor",
"value_string": "5"
},
{
"label": "Yoga",
"value_string": "8"
},
{
"label": "Recreation",
"value_string": "9"
},
// rest of filter values
]
},
// rest of filters
]
Given the fact that those filters are dynamic and user defined is there a way of sending them back with a list products query in graphql? I would expect to have a property somewhere under the products query that could be an array of aforementioned filter objects but so far I haven't found anything neither in the schema nor in the official documentation.
Did anyone have any similar experience with this?
No. Theres no way of getting the filtered options sent back. There are options where you can return the additional filtering abilities (similar to when you are viewing a category page) to return list of ways to filter but nothing that returns the current active filters in place.
{
products(filter: {sku: {like: "%"} } pageSize: 500) {
filters{
request_var
name
filter_items{
label
value_string
}
}
items {
id
sku
name
...
}
}
}
I'm trying to group graphQL queries to have a more organized response.
I want to make a query for allEmployees and get back something in the following format
GraphQL Query
{
Employees:allEmployees{
id
firstName
lastName
}
}
Response
{
"data": {
"Employees": [
"new":[
{
"id": "1",
"firstName": "James",
"lastName": "Test"
},
{
"id": "3",
"firstName": "Charles",
"lastName": "Tes"
}
],
"updated":[
{
"id": "4",
"lastName": "Test"
},
],
"deleted":[
{
"id": "1",
},
],
}
}
}
I've looked into a few options to get named sub-request( like new, updated and deleted) via aliases on fragments but that doesn't seem to be a thing. I've looked at unions, but that doesn't seem to be what I'm looking for.
Ideally I would love to query graphql like...
{
Employees:{
new: allEmployees(status:"new"){
id
firstName
lastName
}
updated: allEmployees(status:"updated"){
id
firstName
lastName
}
deleted: allEmployees(status:"deleted"){
id
}
}
but I don't think it is possible to pass a nested query like this.
Is there anyway to do something like this? I'm using graphql with ruby via the graphql-ruby gem.
please let me know if anyone needs more information?
Thanks
Edit
To clarify. We have multiple entities that will follow the new, updated, deleted pattern. Looking to try and get a response where the results are nested inside a parent name/alias (Employees, Users)
{
"data": {
"Employees": [
"new":[...],
"updated":[...],
"deleted":[...],
],
"Users": [
"new":[...],
"updated":[...],
"deleted":[...],
],
...
}
That is why we would want to nest
GraphQL definitely supports nested queries and multiple top-level queries, and graphql-ruby supports these just fine.
If your GraphQL schema looks like:
type Employee {
id: ID!
firstName: String
lastName: String
}
enum Status { NEW, UPDATED, DELETED }
type Query {
allEmployees(status: Status): [Employee!]!
}
then you could write a query
fragment EmployeeData on Employee { id firstName lastName }
query Everyone {
new: allEmployees(status: NEW) { ... EmployeeData }
updated: allEmployees(status: UPDATED) { ... EmployeeData }
deleted: allEmployees(status: DELETED) { ... EmployeeData }
}
That wouldn't have quite the specific form you're looking for – there aren't good ways to add or remove arbitrary levels in your query, like adding an "Employees" label or removing layers from React-style connection records – but it can retrieve the data you're looking for.
Currently having an issue with the relay approach to nested pagination. An example below to illustrate what I mean:
{
"data": {
"locations": {
"edges": [
{
"node": {
"id": "Location_254"
}
},
{
"node": {
"id": "Location_247"
}
},
{
"node": {
"id": "Location_217"
}
},
]
}
}
Here I have 3 locations returned from a query. Now I wanted to paginate on these locations and look at their 'history'.
query {
locations {
edges {
node {
history(
first:10
after:"eyJzbm9vemVJZCI6Mzg3fQ=="
)
}
}
}
}
This would paginate 10 results after the specified cursor. My issue is, is that this cursor is specific to the location it was obtained from. The cursor it is referring to paginate after, only applies to the location it came from.
Nested pagination tries to paginate on ALL locations here, when in actuality, the cursor being used, was grabbed from a specific location.
Am I seeing this incorrectly, or is there a better way I could be approaching this issue?
Regards, Sebastian