Better way to decode JSON in ReasonML/ReasonReact

Recently I was working on some reasonml/ReasonReact project which required to request data in JSON format from an API endpoint, well there are some BuckleScript decoders such https://github.com/glennsl/bs-json which is the more popular one,
the way you decode is pretty easy:

point = {
  x: int,
  y: int
};

let point = json =>
    Json.Decode.{
      x: json |> field("x", int),
      y: json |> field("y", int)
    };

you pass in the json and define the field in Json.Decode…

at first it was ok to use for basic JSON structures, utill I came across to some deep nested level JSON format, it was so difficult to manually decode it with bs-json.

Someone pointed me to atdge(Atdgen is a command-line program that takes as input type definitions in the ATD syntax and produces OCaml code suitable for data serialization and deserialization.) and realised how stupid I am.

Atdgen allows you to share types in a format call xxx.atd. Where you define all your types in atd file, example in xxx.atd:

type gender = [female | Male| Others]

type person = {
  age: int;
    name: string;
    gender: gender;
}

type people = person list

so you have a list of person where contains some record age, name and gender as variant, so you want to decode this in JSON, its pretty easy with atdgen()

which comes with some Cli commands which allows you to generate the atd file into multiple format. You can install atdgen with opam install atdgen well yes you can install opam from brew

check list of commands from atdgen by calling atdgen --help, lets say we want to generate file type file that can be used in ReasonML project, you can generate the file with:

atdgen -t xxx.atd
atdgen -j xxx.atd

this will product 4 files where you can use it to deal with OCaml Type definitions and JSON.

since we are working with BS(BuckelScript) and we want to generate types and JSON decode for BS, we can use atdgenbs, opam install atdgenbs

atdgenbs -t xxx.atd
atdgenbs -bs xxx.atd

this will again generate 4 files but now we can use it to deal with BS Type definitions and JSON.

To learn how to decode, there is a guide here:

fast piping in reasonml

fast piping allow you to transform your function code into more readable syntax, imaging you have human(person(age())) this is very inconvenience to see. with piping you can do it like this:

age
->person
->human

which is exactly the same as human(person(age()))

there are 3 different pipes as I understand you can do like

age
|> person
|> human

or
human @@ age->person

whats different is that |> will put the parameter on the right side and -> on the left side

person->human("something"); this will take person function and use on the first parameter so it become
human(person, "something");

however if you are using person |> human("something"); it become human("something", person);

and @@ is like wrap into ()

human @@ age->person
is same as human(age->person) which will equals to human(person(age()))

you can readmore here

optional chaining in javascript

Imaging if you need to access deep level of property and you are not sure that if such properties exists deep down, you are doing something like

books && books.book && books.book.authors && books.book.authors.author

This is really difficult to read and understand sometime. there is something called optional chaining in javascript proposal which you can use if you include in babel-plugin-proposal-optional-chaining to your babebl.

The sytax is really easy using ?.

books?.book?.authors?.author all you need is chain the child properties, now everything is so much easier to read.

ReasonML 101 notes

Reason 101:

variable assignment with let keyword cannot is immutable, but you can set it to mutable by assign to ref()

example JS:

let count = 0;
count ++;

in reason:

/* let count = 0; this is immutable */
let count = ref(count);

count := count ^ + 1;

for string concat:

let stringConcat = “some string” ++ variable ++ “another string“;

array in ReasonML is using [|”a”, “b”, “c”|] /* | = pipe symbol */

let test = [|
“a”,
“b”,
“c”
|];

and

list = [
“a”,
“b”,
“c”
];

list is immutable.

in list you can assign a new list like so,

let list = [
  “d”,
  …list
]; /* this is like a appending “d” to a create new list but this is not effective, so use list prime */
let list’ = [
  “d”,
  …list
];  /* notice the single quote beside the name, this is like slightly change of the list with new name list */

Array are really good at random access indexing and accessing
list is really good at appending and create a new list without change

function syntax is same as JS, however In reason everything is return automatically, let say:

let square = x => x * x;
/* this will return x * x * in reason;

Piping for function: piping is like take in the parameter and from left put in the right side…

“string” |> someFunction

this is like someFunction(“string”);

|> is old syntax which takes in the parameter and put it as last argument,

“string” |> someFunction(firstArgument);

and this is like someFunction(firstArgument, “string”);
where new syntax is which will take the parameter and put on left hand side, use |.

“string” |. someFunction(firstArgument);

which is like someFunction(“string”, firstArgument);

piping is really useful when you want to execute multiple level of functions:

example: someFunction(anotherFunction(moreFunction(“string”)))

this is so difficult to read, so do like this:

“string” |. moreFunction |. anotherFunction |. someFunction;

Statement shorthand:
if (x == y) ? true : false;
which is same in reason.

same time you can use if else in reason, however I realised you can’t use just if in reasonml, it has to go with else:

if (x == y) {
  true;
} else {
  false;
}

also in javascript if is statement which means you can’t assign to a variable with if statement, but in reason you can:

let checkIf =
    if (x == y) {
        true;
    } else {
        false;
    }

Pattern match is much:
switch x {
| y => true
| _ => false
}

_ is like all other case …

type variants are like list of variants types, this or that like constructors,

type days =
| Monday
| Tuesday
| Wednesday
….

required to use cap for the naming.

can be good for type checking

example :

switch (day) {
| Monday => “monday”
| Tuesday => “tuesday”
| Wednesday => “wednesday”
}

Using react higher order component

When you start to work with lots of React components, and you realised alot of component patterns are the same, then you want to reuse these component patterns which is where Higher Order Component(HOC) kicks in. Think of HOC as higher order function:

usually you write function in Javascript:

  const thisFunction = function(a, b) {
    return a + b;
  }
  thisFunction(1, 2); // return 3;

Higher order function basically is just a function returns a function.

  const higherOrderFunction = function() {
    const thisFunction = function(a, b) {
      return a + b;
    }
    return thisFunction;
  }

  const getHigherOrderFunction = higherOrderFunction();
  getHigherOrderFunction(1, 2); // return 3

lets take an example at React Components:
Continue reading “Using react higher order component”

React js 16.3

Recently Facebook has released the react 16.3 which bundled with a few awesome features including Context API and createRef(), I will talk abit about Context API since its quite hot topic.

Context API its a feature that allows you to pass your data down to all child levels without passing props around like what you used to do. Lets take below code as example and we will convert to use Context API.
Continue reading “React js 16.3”

Whats wrong with lambda internal server error

Lambda was a great service with great features, and serverless framework is even better, serverless simplified everything you do with AWS or other serverless providers.

Was doing some fun with serverless framework where I am simply trying to output a response from some API to Lambda API gateway, and suddenly I got “Internal server error” with lambda response:

So whats wrong with that? looking in the log it says: “Execution failed due to configuration error: Malformed Lambda proxy response” which means we have some bad format…

Turn out you need to return json format which includes “statusCode”, “header”(no necessary required), “body” as my example below:

  const responseJson = {
    statusCode: 200,
    body: JSON.stringify({
      data: JSON.stringify(response.data)
    }),
  };
  callback(null, responseJson)

Hope this solve your problem with the title.

Udacity react nanodegree review

Recently I was graduated from react nanodegree with Udacity.

The course was separated into 3 main course:

1) React Fundamentals

2) React & Redux

3) React Native

Each course have their own assignment to complete, overall its about 4 or 5 months course, it only took me 1 month plus to complete 😉 since the course itself is little like mix of self pace or not.

You can submit your assignment on their web IDE or on github. The course cost $499 USD, but I would say its quite worth it, the course will assign a mentor to you, you can ask them questions related to the course, they should be happy to answer, sometime if you have different timezone when them, it takes a while for them to reply, but they also have a slack channel where you can ask questions over the channel with other students and some mentors.

Sometime the quiz they gave was pretty tricky, but that helps you think deeper and was overall experience was pretty good.

IntersectionObserver

IntersectionObserver is a very simple and powerful browser API, it really good to build such as lazy-load images, contents or whatever, the concept is really simple, it observer an element, when is visible and then you do something about it. One example, when this div is visible then load image. Outthought its not supported by all browsers at current state, but its well supported by chrome and firefox, and thats enough for now :D.

intserctionObserver

so question is how do you use it?

all you need to do is simple, create an observer

  var observer = new IntersectionObserver(callback, options);

options has 3 different properties which you can use:

  var options = {
    root: ""
    rootMargin: "0px"
    threshold: 0.1,
  }

root: An Element object which is an ancestor of the intended target, whose bounding rectangle will be considered the viewport. Any part of the target not visible in the visible area of the root is not considered visible.

rootMargin: A string which specifies a set of offsets to add to the root’s bounding_box when calculating intersections, effectively shrinking or growing the root for calculation purposes. The syntax is approximately the same as that for the CSS margin property; see The root element and root margin in Intersection Observer API for more information on how the margin works and the syntax. The default is “0px 0px 0px 0px”.

threshold: Either a single number or an array of numbers between 0.0 and 1.0, specifying a ratio of intersection area to total bounding box area for the observed target. A value of 0.0 means that even a single visible pixel counts as the target being visible. 1.0 means that the entire target element is visible. See Thresholds in Intersection Observer API for a more in-depth description of how thresholds are used. The default is a threshold of 0.0.

so all you need to do is observer that this element is visible, do something in callback, but you need to attach the element to this observer when is 10% visible.

so lets attach the element:

  var options = {
    root: ""
    rootMargin: "0px"
    threshold: 0.1,
  }

  var observer = new IntersectionObserver(callback, options);
  observer.observe(document.queryElementById("myElement"));

now you have an element observed, but we have not add callback, so lets do that:

  var options = {
    root: ""
    rootMargin: "0px"
    threshold: 0.1,
  }

  var callback = function(entries) {
    entries.forEach(function(entry) {
      if (entry.intersectionRatio > 0) {
        // do something here.
      }
    })
  }

  var observer = new IntersectionObserver(callback, options);
  observer.observe(document.queryElementById("myElement"));

there you go, easy and powerful.