1 of 20

Relay Error Handling

GraphQL WG Monthly - September 2023

Itamar Kestenbaum

Meta

Ryan Holdren

Meta

Jordan Eldredge

Meta

Tianyu Yao

Meta

2 of 20

Agenda

Why Relay Error Handling?�

Relay Error Handling�

Interop with Other Features�

Progress

3 of 20

01 Why Relay Error Handling?

4 of 20

Current State

01 WHY RELAY ERROR HANDLING?

A feature of GraphQL is that it coalesces errors to null, providing errors as metadata instead of directly throwing exceptions at the network or query level.

5 of 20

The Problem

01 WHY RELAY ERROR HANDLING?

An ecosystem-wide tradeoff (because no GraphQL client has addressed this before):

  • Discard queries with errors or,
  • Not be able to discern whether a null is error or not

6 of 20

The Current Options

01 WHY RELAY ERROR HANDLING?

Essentially, this leaves users with a choice between:

  • Robustness: meaning, “render at all costs” - so if one field errors, everything still returns and that field is null
    • Unable to delineate between errors and true nulls.
    • Users also forget that this is how Relay works - even after they’ve learned about it - and fail to account for that edge case.
  • Correctness: meaning, if something errors, the query throws and nothing is rendered
    • Partially incorrect info never shows.

7 of 20

Other Significant Side-Effects

01 WHY RELAY ERROR HANDLING?

  • If data is being written from the client based on GraphQL Client responses, it can inaccurately overwrite data with null
  • In Javascript, null can be coerced to 0 - so data can potentially be displayed incorrectly in sensitive areas
  • And more…

8 of 20

02 Relay Error Handling

9 of 20

Default: field errors throw

02 RELAY ERROR HANDLING

  • The “null on field-level server error” will be replaced by throwing a JS exception on render by default.
  • Opt-in to old behavior can be done with a @catch directive like onErrorReturnNull.

10 of 20

@catch directive

02 RELAY ERROR HANDLING

  • When a field-level error occurs and has a parent with a @catch directive - the read result of the field will include the thrown exception at the field-level.
    • This also allows user to discern errors from legit nulls
  • When @catch has a specification to return null on exception - the user experiences current behavior.

Note: @catch is still in design phase, but this is our current approach

11 of 20

@catch directive - catching

02 RELAY ERROR HANDLING

Query

GraphQL Response

Relay Response

12 of 20

@catch directive - catching at parent

02 RELAY ERROR HANDLING

Query

GraphQL Response

Relay Response

13 of 20

@catch directive - opting back into null

02 RELAY ERROR HANDLING

Query

GraphQL Response

Relay Response

14 of 20

Positive side effects

02 RELAY ERROR HANDLING

  • Full control over response handling
  • Removing ambiguity of legit null from errors coerced to null by the GraphQL.
  • Removes robustness/correctness tradeoff
  • No longer limited to null-or-throw
  • Throwing on read if fragment co-location is used allows much higher robustness.
  • If an ErrorBoundary is used, new throw-by-default behavior can be easily contained.
    • ErrorBoundary refers to a wrapper component that provides a fallback (and any other handling) if it catches an exception thrown in child components. It also allows anything above it to render uninterrupted.

15 of 20

03 Interop with other features

16 of 20

@required

03 INTEROP WITH OTHER FEATURES

The @required directive can be added to fields in your Relay queries to declare how null values should be handled at runtime. You can think of it as saying "if this field is ever null, its parent field is invalid and should be null".

  • If @required throws - that exception would be caught by a @catch on a parent - and provided in the response
  • Eventually @required can be replaced by CCN’s !

17 of 20

Client-Controlled Nullability (CCN)

03 INTEROP WITH OTHER FEATURES

  • Client-Controlled nullability allows for non-nullable fields that return as null to bubble up as null to the nearest parent. It also introduces
    • When CCN is implemented - treat ! as exactly the same as @required inside a @catch.
    • Difference between @catch(to: NULL) and CCN’s ?
      • ? in CCN makes fields nullable, and are useful in the case of null bubbling.
      • @catch(null) catch errors - and default to null

18 of 20

04 Progress

19 of 20

Progress

04 PROGRESS

  • Shared in Relay repo + here at the GraphQL WG
  • Jordan shared a wider view of true nullability - the context of which this fits into.
  • Strawman is nearly ready to be shared widely. Only some ergonomics left to be sorted.
  • Implementation of a prototype already underway. About 50% complete.

20 of 20

tysm