How to improve my codes?


#1

Hi all

On the top of a file, I’ve following definition:

%raw "import Keycloak from 'keycloak-js'";
%raw "const keycloak = Keycloak('config/keycloak.json')";

and this is, how I am using the object keycloak

    let authorize: unit => Js.Promise.t(string) = () => [%raw {|
      new Promise((resolve, reject) => {
        keycloak
          .init({
            onLoad: 'login-required'
          })
          .success(authenticated => {
            if (authenticated) {
              resolve('You are authenticated.');
            } else {
              reject('You are not authenticated');
            }
          })
          .error(function() {
            reject('Failed to initialize');
          });
      })
      |}];

Would you do like I’ve done above, or use @bs annotation?
Or more example:

  let authenticated: bool = [%raw "keycloak.authenticated"];
  if (!authenticated) {
    reject(. Js.Exn.raiseError("Your are not authorized!"));
  } else {

    let token: string = [%raw "keycloak.token"];
    let subject: string = [%raw "keycloak.subject"];
    let idToken: string = [%raw "keycloak.idToken"];

this
let token: string = [%raw "keycloak.token"];
I do not like. How to write it better with @bs.value?

Thanks


#2

These are some sample bindings for the first part (the one that has the success and error functions):

type keycloak;
type init;
type initParam;
type success;
type error;

[@bs.module "keycloak-js"] external keycloak : string => keycloak = "default";

[@bs.obj] external makeInitParam : (~onLoad: string, unit) => initParam = "";

[@bs.send] external init : (keycloak, initParam) => init = "";

[@bs.send] external success : (init, bool => unit) => success = "";

[@bs.send] external error : (success, unit => unit) => error = "";

Then you could use this like:

keycloak("config/keycloak.json")
|. init
|. success(authenticated =>
     Js.log(authenticated ? "authenticated" : "not authenticated")
   )
|. error(() => Js.log("There was an error"));

Which would generate roughly the same code as seen in your example:

import * as KeycloakJs from "keycloak-js";

KeycloakJs.default("config/keycloak.json")
  .init({
    onLoad: "login-required"
  })
  .success(function(authenticated) {
    console.log(authenticated ? "authenticated" : "not authenticated");
    return /* () */ 0;
  })
  .error(function() {
    console.log("There was an error");
    return /* () */ 0;
  });

The first external (@bs.module) is the one that will produce the import statement. I’m using default because BuckleScript doesn’t currently allow external statements that produce default imports like import Keycloak from 'keycloak-js'.

The second external (@bs.obj) allows to create an object that will be passed to init.

After that, it’s all a combination of two things:

  • Abstract types to represent the output of each step
  • @bs.send to be able to pipe one to the next

Take this with a grain of salt, it’s just an example to see how I would go on writing bindings for a library like this. You can refine the types all you want, depending on the semantics of the API, params etc. Hope it helps.


#3

Wow…Awesome Thanks a lot.