Rescript-Relay Fetch Promise resolution seems impossible :(

We are trying to manually fetch a query and resolve getServerSideProps for a nextjs app.

The worst part by far IMO in ReScript is Promises, something that can be done with ease with 2 lines of javascript using async and await is always a HUGE headache in Rescript.

For the life of me, I can not find a way to satisfy the type system and simply resolve a query to a simple Js.Promose.resolve for nextjs.

let getServerSideProps = (ctx: Next.GetServerSideProps.context<props, params, _>) => {
  CheckoutQuery.fetchPromised(
    ~environment=RelayEnv.environment,
    ~variables={
      id: ctx.params.tid,
    },
    ()
  )->Promise.get(res => switch res.node {
    | Some(template) => Js.Promise.resolve({"props": {
        backgroundColor: template.backgroundColor 
      }})
    | None => Js.Promise.resolve({"props": {
        backgroundColor: "#FFFFFF"
      }})
  })

  /* Js.Promise.resolve({"props": { */
  /*   backgroundColor: "#FFFFFF" */
  /* }}) */
}

HUGE thanks in advance!

Looks like the Rescript Relay api is using reason-promise so I think this was causing some type issues.

I have since got it working by using Obj.magic which I am not a huge fan of, is there a better way around this?

let getServerSideProps = (ctx: Next.GetServerSideProps.context<props, params, _>) => {
  CheckoutQuery.fetchPromised(
    ~environment=RelayEnv.environment,
    ~variables={
      id: ctx.params.tid,
    },
    ()
  )->Obj.magic->Js.Promise.then_((response: CheckoutQuery_graphql.Types.response) => {
    switch response.node {
      | Some(template) => Js.Promise.resolve({"props": {
        backgroundColor: template.backgroundColor,
        headerLogo: template.headerLogo,
      }})
      | None => Js.Promise.resolve({"props": {
        backgroundColor: "#FFFFFF",
        headerLogo: None  
      }})
    }
  }, _)
}

Thanks!

The problem I see here is that you try to return a promise from a promise itself (which is something done a lot in JS).
Did you try to directly return {"props"... ?

Can you share the entire error you have from the compiler?

1 Like

Libraries coming with libraries, coming with more libraries and extra concepts. Unfortunate.

async / await is a prime example for only going the happy path, and completely ignoring the error cases unfortunately.

I think the problem here is that the NextJS bindings rely on Js.Promise.t, and not the advanced Promise.t<'a,'e> implementation of aantron/promise (aka reason-promise).

With reason-promise, you first need to map your promise data to the relevant end result you need, and then convert it to a regular promise, which I believe is done with Promise.toBsPromise.

Alternatively, you may adapt Next.res to use Promise.t<...> instead of Js.Promise.t, which would basically couple your bindings to this particular promise lib.

The whole reason why I made rescript-promise is that ppl don’t have to deal with one extra abstraction. Unfortunately the Relay library dictates the usage of reason-promise here, so no way to make this simpler.

2 Likes

This can often be a bomb waiting to explode in your system. Computations can fail and/or cancel in all kinds of ways, and “ease” can hide these failures. Once the system starts returning values you don’t expect, you have to debug and adapt the code to handle the erroneous paths. This often takes more time and effort than handling these things up front.

2 Likes

These are all very good points. I guess I find the API and compiler errors when working with Promises to be very difficult to navigate (just honest feedback).

I absolutely agree with cover all the bases upfront to prevent unwanted errors at a later point in time.

I will take a look into some of the next bindings @ryyppy and see if I can consolidate the implementation to a single promise api. This is definitely what made the issue surface in the first place.

Thanks all!!!

The way to make this simpler is for you to ship the new Promise bindings, so this issue can be resolved. But to borrow your expression, it’s “unfortunate” that that hasn’t happened yet :slightly_smiling_face:

1 Like

Playing the devil’s advocate, but only partially: is it really that bad with async/await? You can wrap the usages in try/catch. And sure, async/await encourages linear style, but likewise, you can write a bunch of .thens without a single .catch.

2 Likes