Skip to content

Latest commit

 

History

History
163 lines (150 loc) · 9.78 KB

2023-10.md

File metadata and controls

163 lines (150 loc) · 9.78 KB

GraphQL WG Notes - October 2023

Watch the replays: GraphQL Working Group Meetings on YouTube

Primary

Agenda: https://github.com/graphql/graphql-wg/blob/main/agendas/2023/10-Oct/05-wg-primary.md

Determine volunteers for note taking (1m, Lee)

  • Benjie

Review prior secondary meetings (5m, Lee)

  • Previous meetings were skipped due to the conference.

Review previous meeting's action items (5m, Lee)

  • Ready for review
  • All open action items (by last update)
  • All open action items (by meeting)
  • ACTION - Benjie: close all action items that haven't received activity in 6 months.
  • Lack of keyword implies this is a query, but we are talking about a selection set.
  • Lee: It's implied that the top is the mutation.
  • Benjie: line 399, “given the following operations”
  • Lee: intent is to show the full operation. That’s why this is perceived as confusing. Roman’s suggestion is correct but incorrect.
  • Lee: okay with this being an incremental thing, and take a partial fix from Roman. But we need follow ups.
  • Benjie: not 100% sure this is the right solution :). Specifically talking about executing a selection…..
  • ACTION: firm up the wording, e.g. replace "selection set" with "operation" or similar.

Client Controlled Nullability and True Nullability Schema (30m, Jordan/Benjie)

  • True Nullability Schema
  • Null-Only-On-Error type (asterisk) RFC
  • Jordan: Product code will do null coalescing and other tricks to deal with nullable-by-default, or will just get issues.
  • CCN gives a solution to this to make it easier to work with; but there's a fundamental issue: these assertions are made "blindly". They can't see if a field is expected to be null normally, or if it's an exceptional case where it's expected to be null, and it will only be null on error.
  • Q: Why do we coerce errors to null?
  • A: We want the client-server relationship to say that the "data" portion is type-safe with respect to the schema - so you know which fields will be there and which will not. Then we get an issue where a field wants to be null because of an error, but the schema says it cannot be null, so we propagate the null to the next level.
  • As we explored this with Relay, we realized that it's not type-safe data, and some "metadata" in the errors object; but actually it's a tree where each value is there, null, or an error. Errors are only separate as an encoding issue.
  • Lee: Agree. Also: forwards compatibility - we want schema changes to be able to be made without breaking older clients. You can always return a subset of the values from a field; but never a super set - never new unexpected values. Nullability is this shape of problem - a union of the thing you can get with null. This is why GraphQL does this the opposite way around to most programming languages - it's never safe to make an output nullable, but it's always safe to make it non-nullable - therefore non-null, adding the !, is the safe behavior.
  • Most schema designers follow the defaults, and the default is nullable to make sure that these changes can be made later.
  • Jordan: Now let's think about "error handling clients". These clients aren't comfortable rendering partial data. Adding Relay to the Ads manager product at Facebook and the coercion story is not comfortable; and we're not alone - we only want to see null when it's really truly null. Relay is exploring error handling approaches. It's common to throw away entire responses if any errors exist. This is the default state for Apollo Client too.
  • Relay wants to be an error handling client that will never render a null that's actually an error, but will contain that in some way. Imagine reading a field on the client is like lazily evaluating the field on the server - and that might throw. So it's like propagating the error from the server until you read it on the client, and then using the client's own error handling mechanisms for that read.
  • This class of clients are doing a lot of work to handle nulls that are never expected to be null; we could be handling that.
  • Desire: communicate to the clients the "true" nullability of these fields. When they meet a true null, they will then know that the value being null is a normal part of operation, not an exceptional case.
  • Two missing pieces:
    1. A mechanism for error-handling clients to see the "true nullability" of the schema, whilst allowing non-error-handling clients to see the expectations that they see today. Sharing the same server, same schema potentially.
    2. Resilient error-handling clients would like to opt-out of null bubbling (and error coercion generally). Give me any data, just tell me it's an error.
  • Lee: Why don't we have the metadata today to accept the garbage and use the errors metadata to determine the null is an error.
  • Jordan: the client can know that; but at type generation time an error-handling client wants to give a non-nullable type if it will only be null on error.
  • Stephen: Result<Option<T>> can become Result<T> if we know it's just the value or an error.
  • Lee: historical validation of this: classic failure mode was before client-side type generation got good, we had Obj-C and Java generating mediocre types and not thinking hard about nulls, and the Java clients often assumed that nulls weren't possible, which was generally true but not always - and then all the clients would NPE. We had to handle this in all the clients at Facebook.
  • Benjie: what we need is what Jordan described as true nullability from the server (source of truth). This will help out greatly with different peoples’ asks. Some people want exceptions, others want default behavior.
  • Benjie: expressing true nullability “nonnull”, “nonOnlyOnError” mutually exclusive.
  • Lee: What's the new semantic information that’s communicated by schema developer? Does the combination of the two for client developers seem great or complicated?
  • Michael: The client can switch null bubbling off is the value prop of this proposal. So unclear how the marking here provides value to the consumer.
  • Benjie: the client still needs to make decisions of every single null they can potentially encounter. The * indicate it will only be null in the exception case. So for a true null-handling client you can know this thing will have a non-null value, otherwise it will be thrown.
  • Michael: Any field could throw error, what’s the benefit of having “”. Unclear about the decision the client can make with the “
  • Jordan: The need for the 3rd state is for bridging the stage of existing clients and the client can handle the null/error/nonnull union types. The middle state will be interpreted differently during the client codegen stage.
  • Martin: @catch?? The actual control? The middle type shouldn’t be too concerned with the codegen?
  • Jordan: if I’m a codegen client, and the field is in the middle state, then I will handle it differently. But I can give you a safe non-null type. Existing client is not a error handling client.
  • Lee: What do we want the default to be? Nonnull modifiers have the effect of creating a different way to create an error bubble. When we introduce “” is that going to be everywhere, or do we want to advise it to use sparsely. ? is either null, or value. Default is the “ambiguous” field. ‘?’ makes it clear that this field is indeed semantically null. “” resolves the ambiguity.
  • Benjie: every single SDL that currently exists, if they wanna introduce this, all these files need to be all modified.
  • Lee: If this proposal is also where you (Benjie) started, I think there is something there, that I think worth figuring out.
  • Stephen: for backend developer who knows nothing about GraphQL “*” will be confusing and “?” is much more intuitive.

Full Schemas (15min, Martin)

  • Terminology + Appendix C: built-in definitions
  • graphql/graphql-spec#1049
  • Related topic. Full schema idea: in Apollo Kotlin we need to be able to validate an arbitrary operation, and we can't do that without knowing which introspection features the schema supports.
  • Ideally there'd be an artifact that can be produced by the server and consumed by the client that includes the "full schema" definition.
  • Source schema document: what we do today, brevity important, written by humans, no-built in types (boring; might conflict)
    • type Query {a: Int} < Valid source schema
  • Full schema document: exhaustive; contains all of the built in types, written by machines, much more verbose. Can be used to determine if the schema opts out of null bubbling or other such things.
  • Currently doesn't contain meta-fields: __type, __schema and __typename. __typename especially is really verbose.
  • There may be unused types in the document - e.g. if ID is not used anywhere it may still exist in the full schema document
  • Apollo Kotlin users often do an introspection query and convert to GraphQL to store into source control; they're already doing this.