Tackling Functional JS

by ilyavf

Lets say we have an api route defined with parameters and we have replacements for them. Using functional approach lets write some code to get the updated url.

GIVEN url = "/albums/:id/title/:action"
OR    url = "/albums/{id}/title/{action}"

WHEN  replacements = {id: 5, action: 'update'}

THEN  output "/albums/5/title/update"

Just for fun lets do this with imperative approach for the 1st example of the url (with ‘:param’).

var url = "/albums/:id/title/:action",
    params = url.match(/:[a-z]+/g),
    replacements = {id: 5, action: 'update'};
params && params.forEach(function (p) {
    url = url.replace(p, replacements[p.slice(1, p.length)]);
});
console.log(url);
// >>> /albums/5/title/update 

Now lets do the same in a functional style. We will use ramda.js as a functional library.

At first, lets write some helpers:

var getParams = _.curry(function (pattern, str) {
  return str.match(pattern);
});
var getParamsColumned = getParams(/:[a-z]+/g);
var getParamsBracketed = getParams(/{[a-z]+}/g);
var getParamName = function (param) {
  return param.match(/[a-z]+/g);
};
var replaceNeedle = _.curry(function (getParamName, params, url, needle) {
  return url.replace(needle, params[getParamName(needle)]);
})(getParamName);

Now lets define the actual action and execute:

var urlReplaceParams = function (url, needles, params) {
  return needles.reduce(replaceNeedle(params), url);
};
console.log(
  urlReplaceParams(url, getParamsColumned(url), replacements)
);
// >>> "/albums/5/title/update"

// OR
url = "/albums/{id}/title/{action}";
console.log(
  urlReplaceParams(url, getParamsBracketed(url), replacements)
);
// >>> "/albums/5/title/update"

Slightly different variant:

var urlReplaceParams = function (url, replacements) {
  return _.reduce(
    replaceNeedle(replacements),
    url,
    getParamsColumned(url)
  );
};
console.log(
  urlReplaceParams(url, replacements)
);
// >>> "/albums/5/title/update"

Unfortunately, in this example the functional way is much more difficult to both implement and read…

JSbin where I played with the code is here.

Advertisements