SkillAgentSearch skills...

Fermata

Succinct native REST client, for client-side web apps and node.js. Turns URLs into (optionally: magic!) JavaScript objects.

Install / Use

/learn @natevw/Fermata
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Fermata

Fermata is a JavaScript REST library that lets you simply state your HTTP requests using clean syntax.

Features:

  • cleanly build URL strings (optional dot syntax — <i>node.js</i>, <i>supporting browsers</i>) and send asynchronous HTTP requests
  • automatic conversion of JSON request/response data
  • easily send raw data and form requests (including files!)
  • full customization of request (method, headers, data) when necessary
  • easy to add custom initialization and transport handlers
  • OAuth 1.0a support — <i>node.js</i>

Fermata is a no-hassle library, compatible with all modern browsers and node.js

Why?

Fermata magically provides a clean JavaScript interface for direct access to any REST interface.

It does this by taking away the pain of URL strings and giving back a polished server response. Fermata works well in modern browsers and even better in node.js. Its API naturally matches the authoritative HTTP documentation, so you always have access to each of your REST interfaces' latest and greatest features. The simple plugin interface makes it easy to provide site-specific defaults, and/or support servers that don't use the standard JSON data format.

The differences are subtle, but the result is magic! In the end, Fermata makes URLs so elegant that there is no need to use — or maintain! — some one-off "wrapper library" for every different service.

Magic?

For production apps you'll want this file on your own server, but for quick in-browser development you can simply include:

<script src="https://raw.github.com/natevw/fermata/master/fermata.js"></script>

This will make Fermata available through a single global variable on the window: fermata

To make Fermata available under node.js, simply:

$ npm install fermata

The examples below assume you import Fermata's module via var fermata = require('fermata');

Alrighty then?

Let's GET started

So you need to fetch a JSON resource from "http://youraccount.example.com/api/v3/frobbles"?

In Fermata, that's just:

var site = fermata.json("http://youraccount.example.com");
site.api.v3.frobbles.get(function (err, data/*, headers*/) {
   if (!err) console.log("The first Frobble is named", data[0].name);
});

Fermata turns even URLs themselves into native JavaScript objects! Each path part becomes a property, and so slashes in HTTP paths simply turn into dot operators on JavaScript objects. When you pass a callback function, Fermata uses the last method call as the request's method. It really couldn't get much cleaner.

Need to add query parameters?

var newAPI = site.api.v4;     // reuses the base URL from above
newAPI.frobbles({ perPage: 10, page: myPageNum }).get(myPageHandler);

This does a GET on http://youraccount.example.com/api/v4/frobbles?perPage=10&page=N, then asynchronously passes the response data to the myPageHandler callback function after automatically converting the raw JSON response text into a ready-to-use object.

Browser behind the times?

Unfortunately, the examples above will only work in node.js, Firefox 4+ and (soon) Chrome. But don't worry! In browsers without JavaScript's upcoming Proxy feature you just need to use parentheses to form URLs, instead of dots:

var newAPI = site('api')('v4');
newAPI('frobbles')({ perPage: 10, page: myPageNum }).get(myPageHandler);

Note how the dot syntax does still work for the final .get; Fermata provides fallbacks for the basic HTTP methods until browsers catch up.

There's no harm in always using parentheses — you'll need them for adding query parameters or avoiding path component escaping anyway. The following all return the same URL string:

site.api.v4['cannot-dot']({key:"val"})()      // requires harmony-proxies support
site(['api/v4'])('cannot-dot')({key:"val"})()
site(['api/v4', 'cannot-dot'])({key:"val"})()
site('api', 'v4', 'cannot-dot', {key:"val"})()

PUT

Of course, it's also easy to update a REST resource with Fermata. Let's set some configuration on "http://youraccount.example.com/api/v3/whoozits/<ID>/repertoire":

(site.api.v3.whoozits[i].repertoire).put({
    tricks: [1,2,3,4]
}, function (error, result) {
    if (!error) {
        console.log("Configuration accepted for Whoozit #" + i);
    } else {
        console.warn(error);
    }
});

You can send data by passing it to the request method before your callback function (and headers by passing them before the data, but plugins usually handle that for you...). Just like Fermata converts the server's raw response into a JavaScript object, Fermata can convert data dictionaries into a variety of raw formats for you: JSON, x-www-form-urlencoded, form-data...

POST

When the HTTP documentation says something like, "To create a Quibblelog, POST it to /utils/quibblelogger":

site.utils.quibblelogger.post({ message: "All your base.", level: 'stern warning' }, someCallback);

Or for cross-browser support:

site('utils')('quibblelogger').post({ message: "All your base.", level: 'stern warning' }, someCallback);

Voilà!

Plugins

Every time you initialize a new Fermata URL, you do so through a plugin. Fermata provides two built-in (high level) plugins:

  1. json — initialized with a base URL string, then simply sends a JavaScript object to the server as a JSON string and expects that the server will reply with JSON too. Passes headers (and X-Status-Code) as the second callback argument.
  2. raw - gives more direct access, whatever text/byte data you pass gets sent verbatim and your callback gets the full response info. This is a handy way to start when adding new plugins (see below).

Many useful REST servers might talk in XML, or require that every request be specially signed with a secret key. Or maybe you just want to build the base URL string from higher-level settings.

Enter custom plugins.

For example, many of the ideas in Fermata originated in a node.js Chargify library we wrote for their payment management API.

Without plugins, setting up Fermata to connect to Chargify is totally possible...but kinda ugly:

var acct = fermata.json({url:"http://" + api_key + ":x@" + site_name + ".chargify.com"});

With the old custom Chargify-specific library this was a lot cleaner:

var acct = chargify.wrapSite(site_name, api_key);

...but of course if we stick with the old custom library, we then have to learn how to use its old custom interface (which was a bit confusing, and didn't support Fermata's dot syntax).

Plugins give us the best of both worlds. Fermata's one magical native API, with useful service-specific smoke and mirrors hiding backstage:

var acct = fermata.chargify(site_name, api_key);
// WHOOHOO NOW WE ARE MONEY MAKING!!!

There's a tiny bit of setup to use plugins from node.js, since Fermata can't actually read your mind:

var f = require('fermata'),
    _fc = require('fermata-chargify');
f.registerPlugin('billing', _fc);        // installs Chargify plugin into our Fermata module, in this case with a less-typical name

f.billing(site_name, api_key);

In the browser, just include any plugins after the script tag for Fermata, and each plugin will be accessible through its default name.

If such a "fermata-chargify" plugin hadn't been published, we could just register an implementation directly:

fermata.registerPlugin('myChargify', function (transport, name, key) {
    this.base = "https://" + api_key + ":x@" + site_name + ".chargify.com";
    transport = transport.using('statusCheck').using('autoConvert', "application/json");
    return function (req, callback) {
        req.path[req.path.length - 1] += ".json";
        transport(req, callback);
    };
});

Note how transport can be extended using other built-in (and/or known-to-be-registered) plugins like 'statusCheck' and 'autoConvert'. Take a look at the detailed documentation below for tips on publishing plugins that can be easily used from both node.js and the browser.

Complete documentation

NOTE: this API may continue to undergo refinement until a stable 1.0 release.

URL proxy

  • fermata.json(base_url) - create a URL proxy object for base_url using the built-in 'json' plugin
  • () - absolute URL as string
  • .method([options, [headers, [data,]]] function) - request targetting callback, returns native XHR/http.ClientRequest object including an .abort() method
  • (string/array...[, object]) - general extension syntax, each type documented below
  • (object) - override query parameters (see $key:value details below)
  • (array) - extend URL with components (without encoding)
  • (string[, string...]) - extend URL (with encoding)
  • [string] - extend URL (with encoding)

Once you create a URL wrapper, you can extend it in various ways:

var api = fermata.json({url:"http://api.example.com:5984"});
var eg1 = api.database._design.app._view.by_date;
var eg2 = api['database']['_design']['app']['_view']['by_date'];
var eg3 = api("database")("_design")("app")("_view", "by_date");
var eg4 = api.database(["_design/app", "_view/by_date"]);

These all result in the same API endpoint. We can dump the URL as a string using an empty ():

eg1() === eg2() === eg3() === eg4() === "http://api.example.com:5984/database/_design/app/_view/by_date";

At any point in the process, you can set query parameters (a leading '$' on a key forces JSON stringification of the

Related Skills

View on GitHub
GitHub Stars331
CategoryDevelopment
Updated9mo ago
Forks22

Languages

JavaScript

Security Score

72/100

Audited on Jun 20, 2025

No findings