Handle graphql schema stitching error in child query - graphql

I am new to graphql and want to understand the concept here. I have this graphql schema (stitched using graphic-tools). Not all cars have registration. So if I query for 5 cars and one car doesn’t have a registration (no id to link between cars and registration), my whole query fails.
How do I handle this and return null for that 1 car and return registration details for the other 4?
{
Vehicles {
Cars {
id
registration {
id
}
}
}
}

If you mark a field as non-null (by appending ! to the type) and then resolve that field to null, GraphQL will always throw an error -- that's unavoidable. If it's possible for a field to end up null in the normal operation of your API, you should probably make it nullable.
However, errors "bubble up" to the nearest nullable field.
So given a schema like this:
type Query {
cars: [Car!]!
}
type Car {
registration: Registration!
}
and this query
{
cars {
registrations
}
}
resolving the registration field for any one Car to null will result in the following because the cars field is non-null and each individual Car must also not be null:
{
"data": null,
"errors": [...]
}
If you make the cars field nullable ([Car!]), the error will stop there:
{
"data": {
"cars": null
},
"errors": [...]
}
However, you can make each Car nullable (whether the field is or not), which will let the error stop there and result in an array of objects and nulls (the nulls being the cars that errored). So making the cars type [Car]! or [Car] will give us:
{
"data": {
"cars": [{...}, {...}, null]
},
"errors": [...]
}

Related

Why can I execute mutation function with null parameter with type being `String!`?

Simple table with one two rows. ID (incrementing int) and test_value (TEXT, nullable).
1. Query
query getData($test_value:String!) {
testtable(where: {test_value: {_eq: $test_value}}) {
test_value
}
}
Variables
{"test_value":null}
Result
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.testtable.args.where.test_value._eq",
"code": "validation-failed"
},
"message": "unexpected null value for type \"String\""
}
]
}
This is a correct that I expect.
2. Mutation
mutation InsertData($test_value: String!) {
insert_testtable(objects: {test_value: $test_value}) {
affected_rows
}
}
Variables
{"test_value":null}
Result
{
data: {
insert_testtable: {
affected_rows: 1
}
}
}
I expect and error (because of test_value:String! declaration), but I don't get it.
Why?
P.S.
testable schema looks like this:
id: Int!
test_value: String
My understanding of your issue: Your schema has a mutation insert_testtable that takes a nullable String argument. When you submit a named mutation operation with a non-nullable String! variable, the GraphQL server does not respond with an error.
The GraphQL spec says that is the expected behaviour for mutations and queries. The spec says that if the type in the schema is nullable and of the same type as the variable, the operation is to be considered valid. This is what's happening for your mutation.
If you are not seeing the same behaviour for the query, it is possible that your GraphQL server implementation differs from the spec. You could check your server docs or their GitHub Issues.
For what it's worth, I checked that AppSync, AWS's GraphQL implementation, produces the expected behaviour for both queries and mutations.

Is there a way to avoid returing keys with null values in Apollo GraphQL?

I have a nullable attribute in a type:
type Person {
job: String
}
And a query:
query Persons() {
persons() {
job
}
}
Whevener I query the object, I always get the job key, either with a string or a null value.
{
"job": null
}
But what I need is the job key to be present in the result only when the job is defined, otherwise I want it to be skipped altogether.
{}
I have tried returning null, undefined and skipping the key from the data, but Apollo always returns the key no matter what.
It is much easier to delete field afterwards:
if (result.job === null) {
delete result.job;
}
To achieve the same result with graphql you'll have to split Person into two types: PersonWithJob and PersonWithoutJob. Return a union from persons query and change your query to something like:
query Persons() {
persons() {
... on PersonWithJob {
job
}
}
}

I can only query with primary keys in GraphQL on Appync?

This problem is boggling my mind.
I'm trying to query an RDS table with a non-primary key inside a graphql query.
Here is the example of two of my queries in appsync
query getloc{
getLocationByCounty(County: "County"){
LocationsID
State
County
}
}
query getLocations{
getLocation(LocationsID: 1){
LocationsID
State
County
}
}
The second query here works, and returns exactly the county with that LocationID.
The first returns the error message: "Cannot return null for non-nullable type: 'Int' within parent 'Locations' (/getLocationByCounty/LocationsID)"
If I change the schema for locations and make LocationsID non-nullable the error goes away, but it
returns null.
{
"data": {
"getLocationByCounty": {
"State": null
}
}
}
My request resolver for the getLocationsByCounty is:
"version": "2018-05-29",
"statements": ["select * from Locations where County = '$ctx.args.County'"]
Here is the response resolver:
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
$utils.error($ctx.error.message, $ctx.error.type)
#end
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
Is this just not allowed in graphQL or is am I doing wrong???
It's worth noting that if I just do this query:
select * from Locations where County = 'County'
in mySQL, it works exactly as intended.

Validation error of type UndefinedFragment: Undefined fragment

I've a graphql-jave v8.0 app running on Spring boot v1.5.10, and I'm trying to utilize 'fragment' feature of GraphQL to fetch limited number of fields with the following schema type definition:
type School {
id: ID
name: String
address: String
age: String
jobTitle: String
...
}
fragment UserFields on School {
age
jobTitle
}
type Query {
user (id: String!): School!
}
schema {
query: Query
}
When I execute this query:
{
user (id: "123")
{
... UserFields
}
}
The expected result should be:
{
"user": {
"age": "12",
"jobTitle": "student"
}
}
However, It results in the following error
"message": "Validation error of type UndefinedFragment: Undefined fragment
UserFields # 'user'",
Off course I can do this with explicitly passing the field name in the query but for the sake of example, I'm interested in utilizing fragment feature of GraphQL.
Any idea what I'm doing wrong please?
Fragments aren't defined in the schema, they're something for letting you create abstractions whilst building complex queries -- the main purpose is to allow you to avoid repetition when querying the same type in multiple parts of your query.
As Andrew said, and as the official docs exemplify, fragments are not defined in the schema but (ad hoc) in the query:
{
user (id: "123") {
... UserFields
}
}
fragment UserFields on School {
age
jobTitle
}
Unconditional fragments (like the one here) are used to avoid repetition. Imagine having multiple places where you want to select age and jobTitle in the same operation.
Conditional fragments, on the other hand, are used to make a conditional selection depending on the concrete interface implementation or union subtype.

Graphql - How to perform where clause

I am new to graphql and I am struggling with a query.
I want to return a user by their email address
I have a type defined call V1User and it has the following fields
id,
email,
password,
role
What needs to change in this query to return a user based on email?
query GetAllV1User {
viewer {
allV1Users{
edges {
node {
id
email
role
createdAt
modifiedAt
}
}
}
}
}
I tried this query
query getV1UserQuery($email: String!) {
getV1User(email: $email) {
id
email
}
}
With these params
{"email": "test#test.com"}
But get the following errors
{
"errors": [
{
"message": "Unknown argument \"email\" on field \"getV1User\" of type \"Query\".",
"locations": [
{
"line": 2,
"column": 13
}
],
"name": "GraphQLError"
},
{
"message": "Field \"getV1User\" argument \"id\" of type \"ID!\" is required but not provided.",
"locations": [
{
"line": 2,
"column": 3
}
],
"name": "GraphQLError"
}
]
}
My Schema is as follows
Name Type Constraints
id ID NonNull Unique
modifiedAt DateTime NonNull
createdAt DateTime NonNull
role String NonNull
password String NonNull
email String NonNull Unique Indexed
Thanks
Hi
This query solved my issue
query getUserForEmailAddressAndPassword($where: V1UserWhereArgs) {
viewer {
allV1Users(where: $where) {
edges {
node {
email
id
createdAt
password
modifiedAt
role
}
}
}
}
}
Along with these query variables
{"where": {"email": {"eq" : "test#test.com"}, "password": {"eq":"te2st"}}}
You can do so by using the where clause and comparison operators.
https://hasura.io/docs/latest/graphql/core/databases/postgres/queries/query-filters.html#the-where-argument
query {
authors (where: {articles: {rating: {_gt: 4}}}) {
id
name
articles (where: {rating: {_gt: 4}}) {
id
title
rating
}
}
}
I wouldn't recommend using the string "where" in your filter clause. Don't try to emulate SQL. What are you trying to filter using the where clause. If it's an email address then the query in your schema should contain user as the field and email as a parameter to that field.
So the first example that you sent is the right way to do it.
Also, avoid declaring queries using verbs like getUsers or getUser. The schema should just declare the query using nouns
Query
{
Users(email:String):[User!]
}
type User
{
id
email
createdAt
otherStuff
}

Resources