Posts tagged JavaScript

In Building Microservices with SenecaJS: Part 1, we finished writing a simple, RESTful microservice for products with hard-coded data. Now it’s time to hook into a real data store and showcase Seneca’s data abstraction layer. In this post, we will be looking at the JSON file store. In the next post, we will swap this out for a MongoDB store.

There are many advantages to using a file store or in-memory store. One of the advantages is the ease of testability since you don’t have to make an actual connection to the data store. You can run your tests on your local machine (in isolation) and you won’t have to worry about the data getting out sync as it maybe if you’re using a shared database.

There is a couple of changes that are needed to use Seneca’s data entity plugin. First, we need to include the dependencies on “seneca-entity” and the type of store we’re interested in using (jsonfile-store). Here is a snippet:

Now we’re ready to start using the file store. But, we don’t have data in our file store yet. So, it’s time to introduce another end-point to our API in which product information can be added (POST’ed).

In the previous snippet, we accessed the ‘products’ collection on the first line. If it doesn’t exist, it will be created with the first save. Then, in our add action/cmd, we saved the record using the save$ method from the entity plugin, capturing the new product information from the request body (assuming it is JSON). We now need to register the end-point by mapping it to our new action. This is done via the web plugin:

In the snippet above, we accessed the ‘products’ collection on the first line. Then, in our getProductById action, we loaded the record using the product id from request parameter. And that’s it. We have a fully functioning service communicating with a real data store. The full project code is listed on GitHub.

On my current project, our client chose to use Seneca to re-platform their entire e-commerce system. Seneca is a microservices framework built on top of the rich Node.js ecosystem. The project required building a bunch of microservices that could serve multiple clients/channels (web, mobile, in-store kiosk, etc). I hadn’t heard of Seneca prior to the engagement. I was hesitant to use it as the client is mainly a .NET shop. However, after a little bit of digging, I’ve come to enjoy working with the framework as it makes building and organizing small bits of business features really fun.

Seneca wasn’t built initially to serve microservices. It was mainly built to truly decouple components and provide plug-and-play architecture where developers can focus on writing business logic, extending that logic easily and, more importantly, replacing it quickly. However, its clean design enables it to be a strong player in the microservices space. Here are some aspects of Seneca that I really like:

It makes no assumption about your architecture/design patterns. Hence, you’re not locked into an MVC-style pattern though you could organize your code in an MVC way if you wanted to

You can use any of the standard test frameworks/strategies that are available in JavaScript or NodeJS

Perhaps the most important aspect of Seneca is the plugin architecture, which allows the development of simple plugins for things like data abstractions, etc.

That said, there are some things to watch out for. Since Seneca makes no assumption about your architecture, you’re left to come up with design patterns and code organization on your own. Also, due to the richness of Seneca (and NodeJS), there is a bit of a learning curve. However, once you get around that, you start moving quite fast. If you like code generators to get started, there is a seneca yeoman generator though it doesn’t appear to be actively maintained (at the time of this writing) so we didn’t use it.

Enough talk, let’s build a simple, RESTful microservice with Seneca. Following the scheme of e-commerce, our service will be dealing with product information for camera widgets/parts. In this post, we will be using hard-coded data but we will swap this out for a real data store (MongoDB or any other data store) in future posts.

There are two interesting bits that warrant mention. Let’s take a look at the first bit:

this.add('role: products, cmd: getProductById', function() {...});

This is Seneca’s way of registering an action (getProductById) on a business feature/pattern (role: products). Whenever Seneca encounters this pattern from a client, it will execute the callback function associated with this code.

In contrast to registering an action, this.act('role: web') executes the action using Seneca’s web plugin. As I mentioned before, Seneca is transport-layer agnostic. The web plugin provides HTTP features (API routing) for the framework. It is responsible for translating url patterns into Seneca action patterns. It is packaged with Seneca by default so there is no need to include it or require it separately. By default, the alias that we have identified above is a GET request to get a product by the passed in ID. As you can see, that url pattern is mapped to our action function getProductById.

The code above starts up the server on port 3000, using the json body parser to exchange data in JSON. Express is another dependency here which is used by the web module.

Now you’re able to fire up your browser or any other REST client (postman) and hit the following end-point:

http://localhost:3000/products/123

You should be able to see the product information listed in JSON format. The full project is listed on GitHub. A sample http POST request for searching is also included in the code. In future posts, we will be looking at using Seneca’s data abstraction plugin and a file store so we’re not hard-coding the data.

Designing APIs is no walk in the park. In many instances, when your API becomes popular, it can be difficult or even impossible to change. Whether it’s a programming language or framework, a good API makes a world of difference for developers who use it.

Needless to say, an API needs to be simple. But what’s equally (or more) important is for an API to be simple to get started with. The point is, you need to have a low barrier to entry for new users. jQuery, as opposed to other JavaScript frameworks, does a fantastic job of allowing new developers to, not only become immediately productive with the framework, but also get excited about JavaScript development in general.

However, when not accompanied with good design principles, simplicity may lead to anti-patterns. For instance, the main strength of jQuery is perhaps one of its major weaknesses. The “kitchen sink” jQuery’s overloaded main method violates the single-responsibility principle of API design. It also violates another characteristic of good APIs; Self-documentation, though I’ll write a separate post on that at a later time. Consider the following use of jQuery’s main method below:

Obviously this function has multiple, vastly different responsibilities at this point. So, it’s best to actually separate out the responsibilities into different, self-documenting functions. And while jQuery appears to be overloading the function, it actually isn’t as there is no inherent overloading in JavaScript. After taking a deeper dive into the source code of jQuery, what’s actually happening is that jQuery is validating the arguments/parameters of the $(argument); call to determine which execution path to take. Here is what’s happening in (simplified) pseudo-code:

If argument is a “string”, then

check if argument is a selector and execute path

check if argument is html (regex) and execute path

If argument is an HTML Node, then execute path to wrap in jQuery object.

If argument is a function, then the “callback” path is taken for DOMReady.

This obviously increases the complexity of the code due to the presence of different execution paths. Thus, the maintainability of the code becomes a problem. Additionally, this impacts testing negatively as there are 7 different scenarios that could go wrong within the same function as opposed to one and only one. It is no surprise that jQuery has one of the highest cyclomatic complexity measures of most JavaScript frameworks out there. See image below (less is better).

The hardest part about writing testable JavaScript code is actually re-imagining your front-end as isolated modules, where the reality is, the pieces of the UI are intertwined. Can a button or hyperlink be a module? What about a content section on the page? It’s not always clear what to consider “self-contained” on a webpage of related content. Though it might be easier in some cases than others.

For instance, a tab panel widget is easy to unit test. For one, it’s an established pattern, but more importantly, it doesn’t interact with other content on the page. It’s truly self-contained. But how often do you need to write your own implementation of tab panels when there is no shortage of UI frameworks? What developers often focus on is business logic. That’s what I intend to cover in this article by looking at a real example from an application I’m working on at OCLC.

Problem

To give a little bit of context, I’m working on a search engine application for library catalogs. Though the main feature to be covered here is that, when users search for a book, let’s say “The Hunger Games,” we would like to know whether a “full” or “partial” preview of the book is available on Google. If so, we should display it. This is an example of book preview for The Hunger Games on Google.

Identifying Functionality

As a first step, we need to identify functionality at a very high level:

Determine book preview availability in Google’s index by passing ISBNs as the key(s) to Google. Google Preview’s Dynamic Links API is needed.

Given that a book preview exists, render the internationalized/localized Google preview image button based on users’ current locale (Google dictates that you use their image button for branding purposes). See image below.

The button can then link to Google for the preview or embed the preview within the current page.

Design and Solution

At this point, we’re at a good place to start designing. So, what should be modularized here? The button? Maybe. But that’s not as important as the call to determine book preview availability. That’s the part that can be truly modular and “self-contained.” That’s the part the can be portable from one application to the next. So, this module is going to be only responsible for the data; the request and response. And while Google suggests injecting a script tag dynamically into the DOM to avoid cross-origin requests, we can use JSONP as that’s exactly what it covers.

Let’s call our module: GooglePreviewAvailability

We will need the following properties on our module:

_locale: the locale to internationalize the image button provided by Google

_url: the JSONP url with the callback parameter

We will also need the following public function:

load([string] ISBNs, [function] callbackFn): passes a list of comma-separated isbn numbers to the call, and a callback function to be executed upon a successful google preview availability response. The callback function parameter allows the caller/client great flexibility as to what to do with the response. In other words, the caller can either attach the response to a UI element or maybe embed book preview (if it’s available) within the same page.

Identifying Testability

At this point, we haven’t written any code. We just have a boilerplate/skeleton of our module. We just need to identify what we’ll test. As a developer, you can test the heck out of your code all day long, but without knowing how to structure your test code, your tests aren’t really helping you. Martin Fowler addresses this in his article on async testing in JavaScript.

I usually structure my tests in similar fashion. I look for the following things to test:

Object creation & default values:
Verify the object is created successfully and the proper defaults are set.

Request, Response, Callbacks:If requests (JSONP in our case) are made or callbacks are provided, verify a successful request along with the parameters sent, the response and whether it was valid and, last but not least, successful callbacks.

Code and Tests

Here is a snippet of our module which only includes the constructor. Note that this relies on John Resig’s implementation of simple inheritance in JavaScript in addition to some other home-grown JS modules:

Now that we’ve validated our parameters, we need to test the request, response and callback function. Note that there is also a little bit of validation here for when to make the call. If you look back at the module, you’ll see that the JSONP call isn’t made if the isbn numbers parameter is the empty string.

google-preview-availability-tests.js – verify the request isn’t made for empty isbn

You will also notice that we only care about two cases in the response; (1) “full” preview and (2) “partial” preview. Google will send back “no view” in the “preview” response field when a book isn’t available for preview. At this point, we’re to do nothing. Here’s how we validate that in Jasmine.

NOTE: The test code contains a bit of duplication for the sake of clarity in this blog post.

Wrap up

The point that I (hopefully) illustrated is that we didn’t necessarily have to tie any specific UI component to a particular module. However, we’ve taken a very specific case of making requests and receiving responses very generic, reusable, portable and, most importantly, testable. Now clients of this feature can call this module and pass in their code for what to do with the button. In our case, we’re making the preview_url to the google image button as an href. Here is an example of a caller of this module:

This code could have utilized the same GooglePreviewAvailability module in order to embed a preview panel within the webpage as opposed to linking directly to Google. That’s the flexibility we get when we think about testability. Enjoy!