Combine several queries in GraphQL - graphql

GraphQL API has the following queries available:
query getUsers {
users {
id
name
}
}
query getUserAge($id: String!) {
user(id: $id) {
age
}
}
Is it somehow possible to combine both of these queries into one so we could get the users' names and ages in one go?

You can batch queries like this check here :

Just wrap one into another [and combine params if necessary]:
query getUsersAndUserAge($id: String!) {
users {
id
name
}
user(id: $id) {
age
}
}
You can use ready functions - https://stackoverflow.com/a/62727903/6124657

Related

Graphql define variable as field

I'm querying a scheme that looks like this:
{
collections {
listings {
tokenid
price
}
tokens {
id
collection
}
}
}
How can I loop through the tokens field and get listings with the tokenid?
I imagine it looks something like this:
{
collections {
tokens {
$id: id
collection
listings(where: {tokenid: $id}) {
tokenid
price
}
}
}
}
If the API supports introspection, you should be able to view the schema documentation and see how it works. You can try to use a GraphQL-capable client, like Insomnia or GraphiQL.
While the exact implementation might require a different structure, my guess will be something like this:
query($id: ID!) {
collections {
listings(tokenid: $id) {
tokenid
price
}
}
}
and you'll need to specify id as a parameter inside the client.

GraphQL query error -- variable is never used in operation

I am performing a request for an individual post from Apollo Server / Express backend.
In the Apollo GraphQL sandbox, the query works and retrieves the correct post, however, the query has a red squiggle identifying an error which reads -
Variable "$getPostId" is never used in operation "Query".
The query is as follows -
query Query($getPostId: ID!) {
getPost(id:"20c9b3ac-afe6-4faa-a3f9-e00ef1b38ccf") {
title
author
id
}
}
The schema is as follows -
module.exports = gql`
type Post {
id: ID!
title: String!
author: String!
}
type Query {
getPosts: [Post]!
getPost(id: ID!): Post
}
...
`
The closest post which seems to address a similar problem I could find is here. However, I can't translate the resolution to my problem.
Why is the error showing (particularly when the query runs successfully)? What needs to be done to stop the error from showing?
Many thanks!
It sounds like
query Query($getPostId: ID!) {
getPost(id:"20c9b3ac-afe6-4faa-a3f9-e00ef1b38ccf") {
title
author
id
}
}
is supposed to be
query Query($getPostId: ID!) {
getPost(id: $getPostId) {
title
author
id
}
}
Or if your query is actually meant to hard-code the ID, then you want
query Query {
getPost(id:"20c9b3ac-afe6-4faa-a3f9-e00ef1b38ccf") {
title
author
id
}
}

Confused why returnPartialData works without a field policy in Apollo Client 3

In my application I am searching for products, then clicking into a product to see more detail about it.
I perform a GraphQL query on each page. The SEARCH query returns type [Product], and the PRODUCT query returns type Product.
// Search page
const SEARCH = gql`
query Search($query: String!) {
searchResults: search(query: $query) {
id
name
images
price
}
}
`
// ProductDetail page
const PRODUCT = gql`
query Product($id: Int!) {
product(id: $id) {
id
name
images
optionSetName
options {
id
images
name
}
price
}
}
`
I have enabled returnPartialData on the PRODUCT query, as some of the fields for that product already exist in the cache from the SEARCH query, and I would like to access them before the server request returns.
I thought I would also have to apply a field policy to reference the pre-existing Product, as I don't know how PRODUCT even knows what its return type is.
However, when I do the following:
const { loading, data: { product } = {} } = useQuery(
PRODUCT,
{ variables: { id: productId, isShallow }, returnPartialData: true }
)
console.log(product)
the following is logged to console (the first is from returnPartialData, the second from server):
Somehow the PRODUCT query has associated itself with the existing Product, without me explicitly writing a cache redirect.
I'm confused how this has occurred? It seems like Apollo must have a reference to the GraphQL schema, and has seen the return type of PRODUCT is Product, then automatically used the id arg to reference the existing product.
Using "#apollo/client": "^3.4.1"
Wow, turns out I had made a field policy ages ago and forgotten about it... xD
typePolicies: {
Query: {
fields: {
product: {
read (_, { args, toReference }) {
return toReference({
__typename: 'Product',
id: args.id
})
}
}
}
}
}

How to generate the same graphql query with different fields

I'm using graphql-tag so i'm going to use that syntax.
Lets say I have this query:
const query = gql`
query user(id: String) {
user(id: $id) {
id
}
}
`
Whats the best patten to reuse that same query document node if on a different call I want the fields username and email in addition to id without having to rewrite the entire query again like:
const query = gql`
query user(id: String) {
user(id: $id) {
id
username
email
}
}
`
I'm using react-apollo on the frontend if that makes things anymore interesting.
Edit:
Just to clarify... something like this
const userIdFrag = gql`
fragment UserId on User {
id
}
`
const fullUserFrag = gql`
fragment FullUser on User {
id
username
email
}
`
const generateQuery = (documentNode) => {
return gql`
query user(id: String) {
user(id: $id) {
...documentNode
}
}
${documentNode}
`
}
const idQuery = generateQuery(userIdFrag);
const fullUserQuery = generateQuery(fullUserFrag);
(The above does work but give me errors from graphql in the console, which leads me to believe this is not something I should be doing)
Based on your comment the following should work:
const generateQuery = (documentNode, fragment) => {
return gql`
query user(id: String) {
user(id: $id) {
...${fragment}
}
}
${documentNode}
`
}
const idQuery = generateQuery(userIdFrag, 'UserId');
const fullUserQuery = generateQuery(fullUserFrag, 'FullUser');
Basically the fragment name used is the actual one that needs to be spread while the whole documentNode object is put at the end, after query's closing bracket
I am not the very expert on the topic, but here is what I have been able to find out. (if you see any mistakes in my assumptions, let me know).
I found this article that makes some good points against dynamically generating gql queries/mutations. It seems like you get some nice benefits with the static approach, although it's a bit more typing.
But, in case you do need to have dynamic fields, I haven't been able to find anything bad about using the #skip directive GraphQL provides. Here the docs ref.
For the case of using it in react-apollo they also have it in their docs.
So, your code can end up looking something like this:
const query = gql`
query user($id: String, $skipUserMeta: Boolean!) {
user(id: $id) {
id
username #skip(if: $skipUserMeta)
email #skip(if: $skipUserMeta)
}
}
`
You just pass the skipUserMeta as a variable alongside the id field.
NOTE: I actually found a video which talks about the exact same approach here

GraphQL non nested relation

I'm trying to have a representation of nodes on GraphQL more akin to what jsonapi would be like http://jsonapi.org/
What I mean is if we take one of the examples on GraphQL
{
hero {
name
# Queries can have comments!
friends {
name
}
}
}
Have a representation that would be more along these lines
{
hero {
name
# Queries can have comments!
friends {
id
}
},
friends {
id, name
}
}
Is that at all possible in GraphQL
Thanks
It is possible, and there's nothing wrong with having a friends field. In GraphQL terms you can have the following part of the schema:
type User {
id: ID
name: String
firends: [User]
}
type RootQuery {
hero: User
friends(forUserId: ID!): [User]
}
And then you can query this as you like – you can ask for friends separately:
{
friends(forUserId: "12") {
id, name
}
}
But the whole idea of GraphQL is that you don't have to do multiple queries to get the information you need. If you just need a list of users – that's a reasonable query, that most people have (with arguments for pagination and so on). With that said, there's no reason to fetch a list of IDs and to send another fetch query for the data right after that.

Resources