@meth decorator-related error due to Reason -> Rescript Migration

Most of the migration has gone smoothly, but I find myself stuck with this error:

 69 │   make(
  70 │     config(~schema=augmentedSchema, ~playground=true, ~context=makeCont
     │ extHandler(driver)),
  71 │   )["applyMiddleware"](middleware(~app))
  72 │ }
  73 │

  This expression has type
    Js_OO.Meth.arity1<Nomos.ApolloServer.middleware => Express.Middleware.t>
  It is not a function.

The relevant Reason code:

ApolloServer.(
  make(
    config(
      ~schema=augmentedSchema,
      ~playground=true,
      ~context=makeContextHandler(driver),
    ),
  )##applyMiddleware(
    middleware(~app),
  )
);

And the relevant bits of ApolloServer.re:

type apolloServerInstance = {
  .
  [@bs.meth] "applyMiddleware": middleware => Express.Middleware.t,
};

[@bs.module "apollo-server-express"] [@bs.new]
external make: config => apolloServerInstance = "ApolloServer";

These were auto-converted to the following Rescript:

{
  open ApolloServer

  make(
    config(~schema=augmentedSchema, ~playground=true, ~context=makeContextHandler(driver)),
  )["applyMiddleware"](middleware(~app))
}

and ApolloServer.res:

type apolloServerInstance = {@meth "applyMiddleware": middleware => Express.Middleware.t}

@module("apollo-server-express") @new
external make: config => apolloServerInstance = "ApolloServer"

I’m somewhat confused by the error, as I believe the auto-translated Rescript code appears correct when it comes to calling a method as defined via @meth, according to the spiffy new decorator docs.

Additionally, the error itself lists the type as Js_OO.Meth.arity1<Nomos.ApolloServer.middleware => Express.Middleware.t>, which would seem to imply the capacity to call the method in the above manner.

What am I missing here?

The object method syntax that was once available in BuckleScript / Reason is not available anymore (we’d need to add extra syntax just to be able to differentiate between a “normal function” and a “method function” with this context), so you need to restructure the bindings a bit to make the code compile again.

Instead of this:

type apolloServerInstance = {
  .
  [@bs.meth] "applyMiddleware": middleware => Express.Middleware.t,
};

[@bs.module "apollo-server-express"] [@bs.new]
external make: config => apolloServerInstance = "ApolloServer";

You should do:

// ApolloServer.res

type t
@send applyMiddleware: (t, middleware) => Express.Middleware.t

@module("apollo-server-express") @new
external make: config => t = "ApolloServer"

then you’d use it like this:

{
  open ApolloServer

  config(
    ~schema=augmentedSchema,
    ~playground=true,
    ~context=makeContextHandler(driver),
  )
  ->make
  ->applyMiddleware(middleware(~app))
}

IMO this is the saner design anyways, because it doesn’t introduce a lot of extra record labels, and confusing [""] syntax and []() precedence rule issues.

2 Likes

Good to know that functionality no longer exists.

Thanks; and agreed, regarding the improvement.

Might be nice to have a more specific error message in such cases, though.