Welcome to Part Two of our series on Node.js Client Libraries. This post serves as our guide to REST client design and architecture. Be sure to check out Part One on Need-To-Know RESTful Concepts before reading on.

Update: Stormpath now secures authentication to your API- without code!

API Encapsulation

Before sinking our teeth into resources and architecture, let's talk about encapsulation. At Stormpath, we like to clearly separate the public and private portions of our API client libraries, aka 'SDKs' (Software Development Kit).

All private functionality is intentionally encapsulated, or hidden from the library user. This allows the project maintainers to make frequent changes like bug fixes, design and performance enhancements, all while not impacting users. This leads to a much greater level of maintainability, allowing the team to deliver better quality software, faster, to our user community. And of course, an easier-to-maintain client results in less friction during software upgrades and users stay happy.


To achieve this, your Node.js client should only expose users to the public version of your API and never the private, internal implementation. If you're coming from a more traditional Object Oriented world, you can think of the public API as behavior interfaces. Concrete implementations of those interfaces are encapsulated in the private API. In Node.js too, functions and their inputs and output should rarely change. Otherwise you risk breaking backwards compatibility.

Encapsulation creates lot of flexibility to make changes in the underlying implementation. That being said, semantic versioning is still required to keep your users informed of how updates to the public will affect their own code. Most developers will already be familiar semantic versioning, so it's an easy usability win.

Encapsulation In Practice

We ensure encapsulation primarily with two techniques: Node.js module.exports and the 'underscore prefix' convention.

Node.js gives you the ability to expose only what you want via its module.exports capability: any object or function in a module's module.exports object will be available to anyone that calls.

This is a big benefit to the Node.js ecosystem and helps improve encaspsulation goals better than traditional JavaScript environments.

Underscore Names

Additionally we use the 'underscore prefix' convention for objects or functions that are considered private by the development team but still accessible at runtime because of JavaScript's weak encapsulation behavior. That is, any object or function that starts with the underscore _ character is considered private and its state or behavior can change, without warning or documentation, on any given release.

The takeaway is that external developers should never explicitly code against anything that has a name that starts with an underscore. If they see a name that starts with an underscore, it's simply 'hands off'.

Alternatively, other libraries use @public and @private annotations in their JS docs as a way of indicating what is public/allowed vs. private/disallowed. However, we strongly prefer the underscore convention because anyone reading or writing code that does not have immediate access to the documentation can still see what is public vs private. For example it is common when browsing code in GitHub or Gists that annotations in documentation are not easily available. However, you can still always tell that underscore-prefixed methods are to be considered private.

Either way, you need to consistently convey which functions to use and which to leave alone. You may want to omit the private API from publicly hosted docs to prevent confusion.

Public API

The public API consists of all non-private functions, variables, classes, and builder/factory functions.

This may be surprising to some, but object literals used as part of configuration are also part of the public API. Think of it like this: if you tell people to use a function that requires an object literal, you are making a contract with them about what you support. It's better to just maintain backwards and forwards compatibility with any changes to these object literals whenever possible.

Prototypical OO Classes

We use prototypical inheritance and constructor functions throughout the client, but the design reflects a more traditional OO style. We've found this makes sense to most of our customers of all skill/experience levels.

Stormpath is a User Management API, so our classes represent common user objects like Account , in addition to more generic classes, like ApiKey . A few classes used as examples in this post:

Client

ApiKey

Application

Directory

Account

Builder Functions

Node.js and other APIs often use method chaining syntax to produce a more readable experience. You may have also heard of this referred to as a Fluent Interface.

In our client, it's possible to perform any API operation using a client instance. For example, getApplications obtains all Applications by using the client