Is there a way to avoid returing keys with null values in Apollo GraphQL? - 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
}
}
}

Related

WPGraphQL "where" is not case-sensitive

Hi there I am using the WPGraphQL Plugin, however, I am having trouble with the query clause where:
query getCaseStudy {
caseStudies(where: {name : "something-like-this" }) {
nodes {
databaseId
}
}
}
the above code returns a valid and correct response, however, when I passed on the parameter name, like this:
query getCaseStudy {
caseStudies(where: {name : "something-like-this-" }) { //additional special characters
nodes {
databaseId
}
}
}
The results were still the same and the response was valid. Is this how the WPGraphQL works? I want to make it case-sensitive; is there a way to do it?

Postman, test Graphql response

I have this query:
query SessionQuery {
cliente {
id
clienteId
rut
porcentajeDeCompletitudDeInformacion
fichaCliente {
tipoPersona
razonSocial
}
representantesLegales {
edges {
node {
rutRepresentante
}
}
}
documentosRequeridos {
edges {
node {
iDDocumento
cargado
nombreDocumento
tipoDocumentoHQB
}
}
}
}
usuario {
id
usuarioId
email
nombre
rut
}
}
I'm testing for the first time GraphQL through Postman, like this way:
I'm having this response, I don't understand the error message:
{"data":{"cliente":{"id":"Q2xpZW50ZTow","clienteId":0,"rut":"XXX","porcentajeDeCompletitudDeInformacion":20,"fichaCliente":{"tipoPersona":2,"razonSocial":"ING. Y SISTEMAS BIZWARE (Empresa Relacionada)"},"representantesLegales":{"edges":[{"node":{"rutRepresentante":null}}]},"documentosRequeridos":{"edges":[]}},"usuario":{"id":"VXN1YXJpbzoyMDI4","usuarioId":2028,"email":"XXXX#gmail.com","nombre":"XXXX","rut":"XXXX"}},"errors":[{"message":"GraphQL.ExecutionError: Cannot return null for non-null type. Field: rutRepresentante, Type: String!.\r\n at GraphQL.Execution.ExecutionStrategy.ValidateNodeResult(ExecutionContext context, ExecutionNode node)\r\n at GraphQL.Execution.ExecutionStrategy.ExecuteNodeAsync(ExecutionContext context, ExecutionNode node)","locations":[{"line":14,"column":11}],"path":["cliente","representantesLegales","edges","0","node","rutRepresentante"]}]}
I not sure what it means the error. My problem is when I call this Graphql endpoint from JavaScript I have a CORS problem in my app, but I detected with Postman that maybe the problem is this one, and the query or something is broken. Any idea please, thanks.
xadm's comment is correct - in a standard GraphQL schema, the exclamation point means that the field is required. It's likely that the rutRepresentante field is NULL for the database record that your query retrieves.
Either remove the exclamation mark from String! in order to make the field nullable, or populate the row in the database for the rutRepresentante column (or key, if you're not using SQL...)

Why graphql-js executor stops resolving child fields that have their own resolvers when the parent resolver return null/undefined?

While writing a lib for GraphQL in JavaScript I stumbled upon a curious behavior. I managed to isolate it in a very simple example. Let's take this server snippet:
const { ApolloServer, gql } = require("apollo-server")
const typeDefs = gql`
type Book {
resolveItSelf: String
}
type Query {
book: Book
}
`
const resolvers = {
Query: {
book: () => {
return null // same behavior with undefined here
}
},
Book: {
resolveItSelf: () => "resolveItSelf"
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
If we query this server with the following query:
{
book {
resolveItSelf
}
}
We get this result:
{
"data": {
"book": null
}
}
So, I was expecting the graphql executor to try to resolve the "resolveItSelf" field (which have its own resolver) even if the book resolver returned null.
A way to get the behavior I expect is to change the book's resolver a little bit:
const resolvers = {
Query: {
book: () => {
return {} // empty object instead of null/undefined
}
},
Book: {
resolveItSelf: () => "resolveItSelf"
}
}
Then we get this result:
{
"data": {
"book": {
"resolveItSelf": "resolveItSelf"
}
}
}
The field is resolved even if the parent is empty !
So my question is why the graphql-js executor stop trying to resolve fields if the parent's resolver return null/undefined, even though requested fields can be resolved on their own ? (Is there a section in the draft that cover this ?)
In GraphQL, null represents a lack of a value. If a field resolves to null, it doesn't make sense for its "child" field resolvers' to be called since they wouldn't be returned in the response anyway.
From the Value Completion section of the spec (emphasis mine):
If the fieldType is a Non‐Null type:
a. Let innerType be the inner type of fieldType.
b. Let completedResult be the result of calling CompleteValue(innerType, fields, result, variableValues).
c. If completedResult is null, throw a field error.
d. Return completedResult.
If result is null (or another internal value similar to null such as undefined or NaN), return null.
If fieldType is a List type:
a. If result is not a collection of values, throw a field error.
b. Let innerType be the inner type of fieldType.
c. Return a list where each list item is the result of calling CompleteValue(innerType, fields, resultItem, variableValues), where resultItem is each item in result.
If fieldType is a Scalar or Enum type:
a. Return the result of “coercing” result, ensuring it is a legal value of fieldType, otherwise null.
If fieldType is an Object, Interface, or Union type:
a. If fieldType is an Object type.
i. Let objectType be fieldType.
b. Otherwise if fieldType is an Interface or Union type.
i. Let objectType be ResolveAbstractType(fieldType, result).
c. Let subSelectionSet be the result of calling MergeSelectionSets(fields).
d. Return the result of evaluating ExecuteSelectionSet(subSelectionSet, objectType, result, variableValues) normally (allowing for parallelization).
In other words, even if a field's type is an Object (and therefore has a selection set of fields that may also be resolved), if it resolves to null, no further execution happens along that path.

How can i search by field of joined table in graphql and nestjs

i create two table tag and tagTranslation.
following is field of each
Tag
id, type, transloations, creaed_at, updated_at
TagTranslation
id, tag_id, name, language
I use graphql, i want to get tag list by type, name and language
{ tags(name:"tag1", language:"en, type:3){
id,
type,
translations{
id,
name,
language,
}
}
}
so I create resolver like following
#Query(returns => [Tag])
tags(#Args() tagArgs: TagArgs): Promise<Tag[]> {
const where = {
...(tagArgs.type) && {type: tagArgs.type}
};
const include_where = {
...(tagArgs.name) && {name: { [Op.like]: `%${tagArgs.name}%` }},
...(tagArgs.language) && {language: tagArgs.language}
};
return this.tagService.findAll({
where: where,
include: {
as: 'translations',
model: TagTranslation,
where: include_where,
required: true,
}
});
}
#Query(returns => Tag)
tag(#Args({name: 'id', type: ()=> Int}) id: number): Promise<Tag>{
return this.tagService.get(id)
}
#ResolveProperty()
async translations(#Parent() tag): Promise<TagTranslation[]>{
const { id } = tag;
return await this.tagTranslationService.findAll({tag_id: id});
}
when i call tags, the query is called twice
first, A query is executed to get the results I want.
but second,
SELECT `id`, `tag_id`, `name`, `language`, `created_at`, `updated_at` FROM `tag_translation` AS `TagTranslation` WHERE `TagTranslation`.`tag_id` = 1;
query is called once more, so i can't get results what i want.
I think second query is called because of ResolveProperty, I remove ResolveProperty. after that, tag query is not include tagtranslation info...
how can i solve that problem ? or is there another idea??
how can i solve that problem ? or is there another idea??
Relations between entities should be resolved on a field resolver (#ResolveProperty()) level because when someone requests only id and type, you will still perform additional, not needed join on TagTranslation in sql query.

Handle graphql schema stitching error in child query

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": [...]
}

Resources