Netflix / dgs-framework

GraphQL for Java with Spring Boot made easy.
https://netflix.github.io/dgs
Apache License 2.0
3.06k stars 295 forks source link

bug: Optional null fields are not returned #1936

Closed AlexanderPruss closed 3 months ago

AlexanderPruss commented 3 months ago

EDIT: Turns out to be a spring configuration error, other dependencies were reconfiguring the jackson object mapper. See the resolution below.

Observed in DGS 8.7.1 - null return values are not being returned.

Expected behavior

Given the following schema

type Query {
  fetchFoo : Foo!
}

type Foo {
    required: String!
    nullable: String
}

and a query asking for both fields

query GiveMeAllMyFieldsPlease {
    fetchFoo {
        required
        optional
    }
}

and a server that contains a Foo object with required := "required", optional := null,

then the DGS query should return with

{
  "data": {
    "fetchFoo": {
       "required" : "required",
       "optional" : null
    }
  }
}

Actual behavior

The optional field is not returned; the response ends up being

{
  "data": {
    "fetchFoo": {
       "required" : "required",
    }
  }
}

This runs counter to the graphQL spec - https://spec.graphql.org/draft/#sec-Value-Completion - and breaks some client integrations, such as the one from Apollo.

Steps to reproduce

Start a DGS server with the above schema, execute the query against it. Or more generally, just query an optional type that ends up being null.

AlexanderPruss commented 3 months ago

Could this be a configuration error? Is there a way I can poke at the serializer inside of DGS?

srinivasankavitha commented 3 months ago

I don't seem to be able to reproduce this behavior. I do see the null fields if they are optional and requested for in the query.

query {
 movies {
    title
    director
   }
}

where director is a. nullable field:

{
  "data": {
    "movies": [
      {
        "title": "Crouching Tiger",
        "director": null
      },
      {
        "title": "Black hawk down",
        "director": null
      },
      {
        "title": "American Horror Story",
        "director": "Scary movie director"
      },
      {
        "title": "Love Death + Robots",
        "director": "Scary movie director"
      }
    ]
  }
}
srinivasankavitha commented 3 months ago

Separately, are you using the new spring-graphql integration: https://netflix.github.io/dgs/spring-graphql-integration/? If not switching to that would be good as well.

AlexanderPruss commented 3 months ago

Sounds like a configuration problem then. I'll update if I can fix it locally, maybe that can help someone else

AlexanderPruss commented 3 months ago

Fixed it locally, so closing this ticket.

DGS uses Jackson; the Custom Object Mapper DGS Documentation suggests that this can customized by adding a Jackson2ObjectMapperBuilder to the Spring Context. This doesn't prevent other autowired configurations from then further customizing the object mapper, however; this is what was happening in our case. Spring magic doing spring magic things.

If you run into this, try and hunt down where the ObjectMapper is being reconfigured. In our case, it was simpler to explicitly create a not a Jackson2ObjectMapperBuilder bean, as the docs suggest, but rather the MappingJackson2HttpMessageConverter itself.