How are you dealing with nested optional structures (GraphQL)


#1

Hi!

When working with something like GraphQL, you’re often confronted with nested structures with lots of optionals (and Js.Nullable.t). I’m interested in how you typically deal with those types of structures in an ergonomic way. I thought we could gather the alternatives here.

In JS it’s easy enough with optional chaining, and I believe there’s a similar ppx in Reason, right?

One alternative is also to just use switch + Js.Nullable.toOption manually. This becomes quite messy quick though.

So, how are you doing it?


#2

I find @jaredly’s get_in ppx is the best for dealing with GraphQL results (it’s the third recommended option in this section https://github.com/apollographql/reason-apollo#access-deeply-nested-optional-objects)

The only drawback is error reporting can be wonky (lots of line 0 errors). Still a decent tradeoff :wink:


#3

You can use https://bucklescript.github.io/bucklescript/api/Belt.Option.html#VALflatMap for optional chaining in BuckleScript. You could even create an operator alias for it, e.g. let (>>=) = Belt.Option.flatMap;.

Once (let*) binding operators syntax lands, that will be even easier to read and would be my preference.


#4

Thank you for your answers! I had no idea you could define that as an operator, that is very cool.

@yawaramin do you have an example of using that operator for a structure nested in multiple levels? And how do you think the syntax will look once let* lands (and when will it, is it a BS 6 thing or later even?)?.


#5

You should expect it in about a year or ten


#6

Let* syntax shipped recently in OCaml 4.08 and will take some time to flow downstream into BuckleScript, see https://github.com/BuckleScript/bucklescript/issues/1326 to track.

Here’s a great post that shows how to handle nested optionals using all three styles, nested switches, bind operator, and let* syntax: http://jobjo.github.io/2019/04/24/ocaml-has-some-new-shiny-syntax.html


#7

Thank you! That’s an interesting article and I’m glad there’s quite a few alternatives.


#8

do you have an example of using that operator for a structure nested in multiple levels?

Wanted to chime in about an example using that operator since this is how we usually do it too! Converting the first option from https://github.com/apollographql/reason-apollo#access-deeply-nested-optional-objects

let (>>=) = Belt.Option.flatMap;

let deviceName =
  (response##user >>= (user => user##device) >>= (device => device##brand))
  ->Belt.Option.mapWithDefault("", brand => brand##name);

Edit: sorry just noticed there was already an OCaml example in the excellent link already posted!


#9

Your example is illustrative too. One thing, I think you can get rid of most of your parentheses thanks to the precedence of the >>= operator.