How to use variable for Hasura query? - graphql

I am trying to make a request that takes a variable for the distinct_on parameter, but what I have doesn't seem to work:
query customers($distinct: String!) {
customers(limit: 20, distinct_on: $distinct) {
startDate
endDate
}
}
I am assuming the String type is not what is expected, what type should I be using for $distinct?

The type for your variable will be a table-specific enum as documented here.
Your entire schema should be viewable through the GraphiQL interface of the Hasura console -- you can use this to lookup types for fields and arguments. You can also check the error returned by the server -- it will include details about what went wrong with your query, including the type that was expected.

Related

Filtering a list of values by a field value in GraphQL

So I'm doing some tests with GraphQL, and I'm failing in doing something that I believe is fairly simple.
When going to the GraphQL demo site (https://graphql.org/swapi-graphql) I'm presented with a default query which goes like this:
{
allFilms {
films {
title,
director,
releaseDate
}
}
}
This works as expected and returns a list of films.
Now - I would like to modify this query to return only the films where the director is George Lucas, and for the life of me - I can't figure out how to do that.
I've tried using the where and filter expressions, and also change the second line to films: (director: "George Lucas") but keep getting error messages.
What's the correct syntax for doing that?
Thanks!
If you check the docs of the provided GraphQL schema, you'll see that this is not possible. Following is the definition of the allFilms field:
allFilms(
after: String
first: Int
before: String
last: Int
): FilmsConnection
As per the doc, it has 4 input arguments, which are after, first, before, and last. There is no way to filter this out using the director's name.
GraphQL is not SQL. You cannot use expressions like WHERE or FILTER in GraphQL. The schema is already defined and the filters are pre-defined too. If the schema does not allow you to filter values using a certain field, you just can't do it.
You can to see the graphql schema here https://github.com/graphql/swapi-graphql/blob/master/schema.graphql
The allFilms query does not contain a filter for the field director. Also i can't find other query with this filter.
Most likely you need to write a filter on the result of the query.

Type error with Hasura array data type: "A string is expected for type : _int4"

I have a table I created in the Hasura console. A few of the columns are integer int types and I get the expected data type: Maybe<Scalars['Int']>.
However, a few needed to be an array of integers so I created those in the Hasura SQL tab:
ALTER TABLE my_table
add my_ids integer[];
If I populate those in GraphiQL with the following query variable everything works just fine:
{
"my_ids": "{1200, 1201, 1202}",
}
However, when I try to make the same request from my front-end client, I received the following error: A string is expected for type : _int4. Looking at the datatype, it is slightly different than the preset (in the data type dropdown) integer types: Maybe<Scalars['_int4']>.
Is there a way to get the array of integers to be Maybe<Scalars['Int']> like the preset integer types? Or if there isn't, how can resolve the issue with my request throwing errors for this _int4 type?
Hasura cannot process array but it can process array literals.
I've written a function to help you to transform your array into array literal before mutation:
const toArrayLiteral = (arr) => (JSON.stringify(arr).replace('[', '{').replace(']', '}'))
...
myObject.array = toArrayLiteral(myObject.array) // will make ['friend'] to {'friend'}
Good luck

custom scalar type as input arguments in graphql

I defined a custom scalar type: DateTime (based on joda time library) in graphql schema. I see that in the Graphiql UI schema definition and a scalar line at the top of the schema definition.
however, I couldn't find out the syntax of including this as an argument in the query.
for ex, how do I send values of MyDateTimeType in the below query
query {
fetchData(key:"1", dateArg: MyDateTimeType) {
field1
}
}
Actually, it depends on how the MyDateTimeType's coerceInput method is defined. In my case, the coerceInput has a match case statement with StringValue case, so it worked when I passed a String to it. dateArg:"2019-05-30"

Is it a bad practice to use an Input Type for a graphql Query?

I have seen that inserting an Input Type is recommended in the context of mutations but does not say anything about queries.
For instance, in learn tutorial just say:
This is particularly valuable in the case of mutations, where you might want to pass in a whole object to be created
I have this query:
type query {
person(personID: ID!): Person
brazilianPerson(rg: ID!): BrazilizanPerson
foreignerPerson(passport: ID!): ForeignerPerson
}
Instead of having a different type just because of the name (rg, passport) of the fields, or put one more argument like type in query, I could not just have the Person with an documentNr field and do an Input type like that?
input PersonInput {
documentNr : ID!
type: PersonType # this type is Foreign or Brazilian and with this I k
}
PersonType is a enum and with him I know if the document is a rg or a passport.
No, there is nothing incorrect about your approach. The GraphQL spec allows any field to have an argument and allows any argument to accept an Input Object Type, regardless of the operation. In fact, the differences between a query and a mutation are largely symbolic.
It's worth pointing out that any field can accept an argument -- not just ones at the root level. So if it suited your needs, you could easily set up a schema that would allow queries like:
query {
person(id: 1) {
powers(onlyMutant: true) {
name
}
}
}

Understanding GraphQL Union types

While experimenting with the Union types in GraphQL here: https://graphql.github.io/learn/schema/#union-types I ran into the following:
I initially thought that the fields you specify in the query are the fields that going to be searched for the text: "Millenium", however that's not the case because I'm still getting the Millenium Falcon's data even after removing the name field from the query for the Startship type.
I did another test: R2-D2's primaryFunction is Astromech, if you search for Astromech you'll get nothing, even if primaryFunction is specified for Droid type.
Note that name is still specified on Starship because otherwise it wouldn't show up in the results given that Starship is not a Character!
That simply means that because we are using a Union type, given two types that are part of the Union that both have a name field, you still have to request the name field for each type in their inline fragment. Omitting the name for the Starship fragment, but including it on Character, means if the returned type is a Character the name field will be present but it will not be present on the Starship type.
The docs are mentioning this to highlight the difference between Unions and Interfaces. If SearchResult was an Interface that included the name field and Character and Starship implemented that Interface, you could do something like this instead:
{
search(text: "an") {
name
__typename
... on Human {
height
}
... on Droid {
primaryFunction
}
... on Starship {
length
}
}
}
But because Unions don't guarantee any fields are shared between their types, it's not possible to do so with Unions.
With regards to search, that's not something that's baked into GraphQL. This particular schema happens to have a search field on its Query type and that field resolves a particular way. If you were creating a server, you could write a search field that considered the requested fields as part of the search criteria. But this is an implementation detail and not related to how GraphQL works in general.

Resources