GraphQL: Remove field from query string - graphql

I have a graphQL server consumed by many clients and have a process that generates operations from introspection; problem is that the schema has a handful of nested queries that take arguments that I may or may not want to invoke.
given this generated operation
query Query($input: String!) {
things(input: $input) {
item1
item2
nestedQuery(nestedInput: $nestedInput) {
nestedItem1
}
}
}
is there a tool (other than string parsing, that's a given) to strip unwanted fields from here so that the query is transformed into
query Query($input: String!) {
things(input: $input) {
item1
item2
}
}
Looking at the introspection JSON I can identify this item by the presence of args on the field things that is past the first depth - but I don't want to necessarily lose information on generation - I'd like those nested queries to be visible/documented.

I still don't understand how you are generating the GraphQL document here, but assuming that you have total control over it, you can use the default directives (#skip and #include) to skip or include fields based on a condition.
For example, the following document will skip the nestedQuery field when executing. You may use a variable value as the value for the argument if.
query Query($input: String!) {
things(input: $input) {
item1
item2
nestedQuery(nestedInput: $nestedInput) #skip(if: true) {
nestedItem1
}
}
}

Related

Contentful GraphQL filter with relational queries and reference fields

I'm currently trying to filter entries with a field references, many.
In other words, the field takes multiple locations with each locations consisting of city among other fields.
For my query I want to get every entry that has a location with a specific city name set.
The following query filters an entry that takes only on reference for location, how would it look like when having many?
export const NEWS_ARTICLES = gql`
query GetNewsArticles($location: String) {
entryCollection(
where: {
location: { city: $location }
}
) {
items {
location
}
}
}
`;
Pulling GraphQL's schema all I get is locationCollection_exists - is this even possible?
I found the following article, which seems to do what I desire, but for the Filter API and not GraphQL: https://www.contentful.com/developers/docs/concepts/relational-queries/
Contentful DevRel here. 👋
Filtering by a linked collection entry is not supported right now. What you can do though it flip the query around.
export const NEWS_ARTICLES = gql`
query GetNewsArticles($location: String) {
cityCollection(
# your filter
) {
items {
linkedFrom {
# all the entries linking to this entry
}
}
}
}
`;
You can find more information about this approach in the docs or this blogpost.

GraphQL How to get all countries based on a selected continent code

I am using the following GraphQL schema and want to find out how to get all the countries based on the continent code.
https://countries.trevorblades.com/
query GetCountriesByContinent($code: String!) {
countries(filter: {
continent: {
???
}
})
}
Any ideas?
UPDATE: The following code works but I am not sure how continent is match against the code.
query GetCountriesByContinent($code: String!) {
countries(filter: {
continent: { eq: $code }
}) {
name
}
}
UPDATE 2:
It might be that behind the scene when you compare a type with something it always compare using the ID field.
To better understand your query let's break it down
countries(filter: {
continent: { eq: $code }
})
countries - find all countries
filter - filtered by
continent - continent (field)
eq - equals to
$code - code (passed as argument)
In this API field code acts as an ID so behind the scenes they compare by continent.code. That logic of comparison and filtering is happening on the server-side implementation. The developer of that API can choose how he wants to implement comparison
You can also explore docs and schema on the right-side panel in Grahpql Playground and you can see possible options:
input CountryFilterInput {
code: StringQueryOperatorInput
currency: StringQueryOperatorInput
continent: StringQueryOperatorInput
}
That means you can filter countries by code currency and continent
input StringQueryOperatorInput {
eq: String
ne: String
in: [String]
nin: [String]
regex: String
glob: String
}
eq: is exactly the filter value.
ne: is anything except for the filter value.
in: matches any element in given array
nin: matches none of the elements in given array
lt: is lower than the filter value
lte: is lower than or equal to the filter value
gt: is greater than the filter value
gte: is greater than or equal to the filter value
regex: matches given JavaScript regex
glob: matches given micromatch pattern
It looks like query filters used in Gatsby to get more details
Reference docs: https://www.gatsbyjs.com/docs/query-filters/#supported-comparators

Loading __typename fields in seperate queries Apollo-Client not Updating UI

I'm attempting to load information about a type in 2 steps (since the info I'm asking for in secondQuery will take some time to load):
Component:
const MyComponent = ({startDate}) => {
const firstQuery = useQuery(
GET_INFO_PART_ONE,
{
variables: {startDate}
}
);
const secondQuery = useQuery(
GET_INFO_PART_TWO,
{
variables: {startDate}
}
);
}
Queries:
export const GET_INFO_PART_ONE = gql`
query getInfoPartOne(
$startDate: DateTime!
) {
infoPageResults(
startDate: $startDate
) {
edges {
info {
infoID
infoFieldOne
infoFieldTwo
infoFieldThree
}
}
}
}
`;
export const GET_INFO_PART_TWO = gql`
query getInfoPartTwo(
$startDate: DateTime!
) {
infoPageResults(
startDate: $startDate
) {
edges {
info {
infoID
infoFieldFour{
netRate
}
}
}
}
}
`;
When I do this and both queries resolve, the cache's ROOT_QUERY includes the data as I would expect it, with infoPageResults containing an array of edges where each edge's info __typename includes the fields specified in the GET_INFO_PART_ONE and GET_INFO_PART_TWO queries. I would then expect firstQuery.data.infoPageResults.edges in the above component to include the fields loaded from the second query.
The Problem
After both firstQuery and secondQuery are finished loading, firstQuery.data.infoPageResults.edges does not contain the fields loaded by secondQuery, even though the cached values look as I would expect them.
Is there something obvious I'm misunderstanding about how the query hooks work?
Is there a better strategy for loading additional fields onto a _typename in 2 steps?
Just caches what was queried ... no node entries cached (additionally, separately - as cache is normalizing cache), because no id field (required by default as unique entry id) ... it can be customized to use infoID for info type (see docs).
Properly cached node (info) entries can be used to display node details (from 1st query) on 2nd query result rendering list ... using additional 'cache-only' policy queries (info node by id) in subcomponents (react).
Start with more standard example/tutorial to explore possibilities.
update
No, data fetched separately are accessible separately ... it's not cache problem and not querying problem...
1st query won't return fields/properties fetched in 2nd query ... by design;
list rendered using 1st result won't be refreshed when 2nd query result will arrive ... if doesn't contain ref/not consume 2nd data;
You can use/pass both data in parallel or combine them (in immutable way) before passing to some view component ('Presentational and Container Component Pattern') ... list can be rendered using one prop and updated when 2nd prop changes.

How can I do a WpGraphQL query with a where clause?

This works fine
query QryTopics {
topics {
nodes {
name
topicId
count
}
}
}
But I want a filtered result. I'm new to graphql but I see a param on this collection called 'where', after 'first', 'last', 'after' etc... How can I use that? Its type is 'RootTopicsTermArgs' which is likely something autogenerated from my schema. It has fields, one of which is 'childless' of Boolean. What I'm trying to do, is return only topics (a custom taxonomy in Wordpress) which have posts tagged with them. Basically it prevents me from doing this on the client.
data.data.topics.nodes.filter(n => n.count !== null)
Can anyone direct me to a good example of using where args with a collection? I have tried every permutation of syntax I could think of. Inlcuding
topics(where:childless:true)
topics(where: childless: 'true')
topics(where: new RootTopicsTermArgs())
etc...
Obviously those are all wrong.
If a custom taxonomy, such as Topics, is registered to "show_in_graphql" and is part of your Schema you can query using arguments like so:
query Topics {
topics(where: {childless: true}) {
edges {
node {
id
name
}
}
}
}
Additionally, you could use a static query combined with variables, like so:
query Topics($where:RootTopicsTermArgs!) {
topics(where:$where) {
edges {
node {
id
name
}
}
}
}
$variables = {
"where": {
"childless": true
}
};
One thing I would recommend is using a GraphiQL IDE, such as https://github.com/skevy/graphiql-app, which will help with validating your queries by providing hints as you type, and visual indicators of invalid queries.
You can see an example of using arguments to query terms here: https://playground.wpgraphql.com/#/connections-and-arguments

The significance of the string immediately after query type (query / mutation) GraphQL

I was wondering what the significance of the string that follows the query type, in this case "ProvisionQueues", it seems removing this from the string doesn't affect anything - is it just for logging or something. meta data?
mutation ProvisionQueues {
createQueue(name: "new-queue") {
url
}
}
That string is the operation name. If you don't specify a name, the operation is known as an anonymous operation. When practical I like to always specify an operation name though, because it makes it easier for doing things like reading stack traces.
it seems removing this from the string doesn't affect anything
You can only use an anonymous operation when you are performing a single operation. For instance, the following results in an error:
query {
user(id: 1) {
name
}
}
query {
user(id: 2) {
name
}
}
The error:
"message": "This anonymous operation must be the only defined operation."
If you want to learn more, you can check out the GraphQL spec:
If a document contains only one operation, that operation may be unnamed or represented in the shorthand form, which omits both the query keyword and operation name. Otherwise, if a GraphQL query document contains multiple operations, each operation must be named.
Adding to #Eric's answer with another example.
query allNotifications {
notifications {
success
errors
notifications {
id
title
description
attachment
createdAt
}
}
} ​
​
query {
users {
errors
success
users {
id
fullName
}
}
}
Notice above that the users query has no operation name. This can be resolved as below.
​
query allUsers {
users {
errors
success
users {
id
fullName
mohalla
}
}
}

Resources