Kyran Burraston

Streamlining web app development with Stubby

If you’re a web developer, chances are you spend a lot of time hooking up applications to various JSON driven web services. Unless you have a test back end already in place, you need to be able to mock the responses your app expects.

There are a few ways of doing this: The simplest method is to point all calls you will make to .json files stored in your project. When you’re ready to integrate with the back end, swap the references over to the real URLs.

The problem

In a perfect world, this would work fine. The problem arises when you need to quickly switch between local and deployed environments (which you inevitably will). Changing these manually in a big app would be long winded and awkward.

By defining references to both environments on every HTTP call, we’re able to refer to them based on an environmental variable —a global development boolean, for example. This mitigates the need for us to rewrite any code, and when deployed, the correct value will be used.

xhr.open('GET', isDevelopment ? 'json/response.json' : '/api/response');

This approach works well, but still it has some flaws. Firstly, it’s verbose. You need to write two references for each request, plus you’ll be deploying redundant code. It works, but it gets messy.

Stubby

The complexity stems from having to perform logic every time we make a request. If we serve our test responses from the same relative paths as our deployed version, we circumvent the problem.

We can do this with a local web server, configured the same as our real one. The best way I’ve found is to use a tool called Stubby, which lets us define endpoints with YAML syntax. I’m using the node version, but there are .NET and Java equivalents.

It can be installed with NPM (with the global flag!):

$ npm install -g stubby

This isn’t anything groundbreaking, the same can be done manually with any server side framework. But this is fast, and really easy!

- request:
    method: GET
    url: ^/api/my/endpoint/$
  response:
    headers:
      content-type: application/json
    file: sample-json.json
    status: 200
    latency: 450

The syntax is self explanatory. We define the HTTP verb, url, headers, status code, and metadata. The data being returned can be a reference to a file or defined inline. By creating multiple response properties, we can cycle through varying responses.

You can also simulate HTTP latency, which stops you forgetting that HTTP calls aren’t instantaneous (as they are when pointing to a file on disk). This feature makes your local set up behave much more like your live version. It’s also very useful for implementing loading spinners!

Proxy

Stubby runs on its own Node server, so we need a way of marrying it to our main dev server. We can do this using a proxy.

I'm using Gulp to start up a server with Node and Express. Using the proxy-middleware package, a proxy can be set up with one line of code.

// requests to /api are proxied to localhost:8882
server.use('/api', proxy(url.arse('http://localhost:8882/api')));

Without doing this, the relative URLs would be pointing to the wrong server. Also, even if the correct server port was specified, we’d run into the cross origin restriction (presuming the Access-Control-Allow-Origin: * header isn't present).

Live data locally

One of the benefits I've found most useful is the ability to test live data on my local machine. To do this we need to use a global variable with our apps URL. In the code below I've used a var, however it's a great example of where const could be used, were browser support more wide spread.

var ENV = 'http://application-url.co.uk/';

$http.get(ENV + 'api/resource', callback);

Now, all calls will be made to the absolute path. There's a little overhead doing this, but it allows us to really easily switch between and diagnose issues with different environments. Providing the ENV variable is only ever an empty string when deployed, there's no problem.

If you do run into the cross origin restriction, you can run Chrome from the command line with the disable web security flag to bypass it.

$ open -a /Applications/Google\ Chrome.app --args --disable-web-security

With both servers up and running and the proxy in place, we've make the process of building and testing an app much simplier. With virtually no changes we can run our in three environments – locally with local data, locally with live data, or live with live data!