I'm new to GraphQL and I'm using WPGraphQL and WooGraphQL.
Their top level connections allow me to expand both nodes and edges like so:
{
wpgraphql {
productCategories {
# What's the difference between these?
# 1) top-level nodes
nodes {
id
name
}
# 2) top-level edges
edges {
node {
id
name
}
}
}
}
}
Which returns a response like so (IDs omitted):
{
"data": {
"wpgraphql": {
"productCategories": {
"nodes": [
{
"name": "Accessories"
},
{
"name": "Gift Cards"
},
{
"name": "Indoor"
}
],
"edges": [
{
"node": {
"name": "Accessories"
}
},
{
"node": {
"name": "Gift Cards"
}
},
{
"node": {
"name": "Indoor"
}
}
]
}
}
}
}
My question is simply: Which one do I use? Why are there both?
Here is a screenshot of the GraphiQL explorer if that helps.
GraphQL schemas that implement the Relay specification utilize Connection types to model one-to-many or many-to-many relationships.
Each connection includes a list of edges and a PageInfo object. Each edge includes a node and the cursor for that node.
Edges may also contain additional fields -- for example, if we have a friends connection between User nodes, we might include the timestamps when the friendships were created. Normally, though, edges are only used for the cursor field they expose. The cursor value is used when paginating through the connection and exposing it for every edge means you can start your pagination from any arbitrary point in the results. The cursor is not included as part of the node because it's may be specific to the connection and not just the node itself (for example, some cursors encode sort criteria).
However, if as a client you don't need to paginate the results of a connection and just want to fetch all the nodes, you probably don't care about cursors. In these scenarios, having edges doesn't add any value and just increases the depth of your query. As a result, as a convenience to the client, some GraphQL services have opted to exposing just the nodes for the connection in addition to the edges.
Related
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?
GraphQL lets you ask for specific fields, the response contains only the fields that you had asked for. For example:
a graphql query like:
{
hero {
name
}
}
will return:
{
"data": {
"hero": {
"name": "R2-D2"
}
}
}
where as a graphQl query like:
{
hero {
name
friends {
name
}
}
}
would return:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke"
},
{
"name": "Han Solo"
},
{
"name": "Leia"
}
]
}
}
}
Is there a similar mechanism/library/pattern that can be used in gRPC to achieve the same?
FieldMask is similar in protobuf. It is a list of fields to retain, so the first example would be paths: "hero.name" and the second would be paths: ["hero.name", "hero.friends.name"].
It is probably most frequently used to specify which fields should be changed in an update. But it can equally be used to specify the fields that should be returned.
The server can either process the FieldMask directly (e.g., only using the listed fields in a SELECT SQL query), or it can retrieve all the information and filter the result using FieldMaskUtil.merge() to copy just the requested fields into a new proto message to return to the client.
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
I am wondering how to deal with the following problem. I am using GraphQL to query the v4 Github API with the following query:
{
viewer {
repositories(first: 30) {
edges {
node {
name
}
}
}
}
}
This gets me a response that looks like so:
{
"data": {
"viewer": {
"repositories": {
"edges": [
{
"node": {
"name": "test-repo"
}
},
{
"node": {
"name": "another-repo"
}
}
]
}
}
}
}
I am pretty new to GraphQL, I understand that in my query I need to provide the edges and nodes but I would rather get a response back in this kind of way because I am not interested to know about "edges" and "nodes" in my frontend:
{
"data": {
"viewer": {
"repositories": [
{
"name": "test-repo"
},
{
"name": "another-repo"
}
]
}
}
}
}
I am guessing this kind of response is normal for GraphQL but it would be pretty cumbersome to rewrite to response all the time for easier usage in my frontend. Is there some way to emit the "edges" and "nodes" and get the formatting that I would like or is this simply all up to me to deal with?
I have looked at some libraries like Apollo but I have no idea is this is a right fit to deal with things like this. Hopefully someone a bit more experienced with GraphQL could tell me something more.
Sometimes, services provides two endpoints: Relay endpoint (with edges and nodes) and simple endpoint.
Looks like GitHub only have a Relay endpoint. In this case, the only thing you can do is to manually format the response on your frontend.
Actually, such complex response structure is needed because we often need to do a pagination. Take a look at the example:
{
getArticle(id: "some-id") {
id
userId
user {
id
name
}
tags(first: 10, after: "opaqueCursor") {
edges {
node {
id
name
itemsCount
}
}
pageInfo {
hasNextPage
hasPreviousPage
endCursor
startCursor
}
}
}
}
pageInfo is located at the same level as edges.
So if you later will need to do a pagination, it would be better to keep the response format as is.
You can remove the edges query if you know you aren't searching along those relationships. Cursor-based pagination will work by checking the pageInfo value hasNextPage and using endCursor as the after query parameter:
viewer {
repositories(first: 30,after:"<CURSOR_STRING>") {
totalCount
pageInfo{
hasNextPage
endCursor
}
nodes{
name
}
}
}
returns
"viewer": {
"repositories": {
"totalCount": 38,
"pageInfo": {
"hasNextPage": true,
"endCursor": "Y3Vyc29yOnYyOpHOAl/5mw=="
},
"nodes": [
{
"name": "AllStarRoom"
},
{
"name": "shimsham"
},
{
"name": "Monitor-Docs"
}
]
}
}
I’m researching for database tool, and i’m not quite sure how Elastic can cope with my requirements.
I have a tree data structure, a family tree.
The root is the first man Adam, and afterward his children, there children and so on.
Elements looks like this (don't care about marriage relations this data just to get the idea) :
{
id: 1
name: “Adam”
parentId: 0
}, {
id: 2
name: “Cain”
parentId: 1
}, {
id: 3
name: “Abel”
parentId: 1
}, {
id: 4
name: “johnny(Cain junior)”
parentId: 2
}, … {
id: 12324568
name: “Cain b”
parentId: 1434
}
Queries I’d like to exec:
‘full text’ search on the element name, response should include the documents and the path to them. Fof example, searching for ‘Cain’ should replay:
a. Adam/Cain
b. ../David/Danny/Cain b
CRUD person by id (Ids are unique)
Get family tree by id, will respond hierarchical tree (nested JSON) , from ‘id’ as root
Tree is about ~20-30 level deep, up to 10,000 elements
Finally, my question:
Can elasticsearch provide me this functionality?
Should i use the parent/child scheme?
How should the index mapping should look.
To answer your questions:
3) Your index mapping could look something like this:
{
"mappings": {
"my_index": {
"properties": {
"id": {
"type": "integer",
"fielddata": true <-- you need this if you're using this field for aggregations
},
"parentId": {
"type": "integer"
},
"name": {
"type": "text" <-- can be text/keyword depending on your requirement
}
}
}
}
}
2) I would suggest you to use the parent-child mapping, so that you can have a one-to-many relationship. Elasticsearch maintains a map of how parents correspond with their children, and query-time joins are fast because of this mapping. You could read up on this SO to know the benchmark of parent-child mapping over the nested.
1) You could always do a full text search as long as you have your mapping type for your field as text. This should help you on identifying the difference of using the type text over keyword. You could add a single document to your index or else you could go with a bulk adding containing multiple documents. This goes hand in hand with other CRUD operations as well. I'm still unaware how the hierarchical tree would respond when you're requesting documents by a parent id.
Hope this helps!