Not actually a prism, LOL.

EDIT 26/6/14: I've had a lot of great feedback from everyone. Gulp support is in experimental mode right now, but if there's anything else you would like to see then I encourage you to post an issue on my repo's issue tracker. Thanks everyone! :)

grunt-connect-prism is a new grunt plugin I've written to help make developing a Single Page Application (SPA) easier. If you're a RoR aficionado then you've probably heard of the project VCR, which is the inspiration for Prism.

The purpose of this plugin is to provide an easy way for you to record HTTP responses returned by your backend API (or some other remote web resource).  After recording you can then replay the responses when requested and disconnect from the actual backend.  It allows you to work independently of the backend.  It's like an HTTP cache that persists cached responses to the disk and is only active when you explicitly turn it on.

I've written a sample project that uses the grunt-connect-prism project. The rest of this blog post will cite examples that are demonstrated in prism-sample-project.

Why would I want to use it?

Speed up development time

Prism is most useful for mocking complex & high latency API calls during development.  Setting up a full stack for your web app can be costly and time consuming.  The backend introduces a number of different variables to your development practices.  In extreme cases, you may not even host it locally or have access to change anything.  Having a way to record & mock calls to the backend can eliminate a lot of troubleshooting cycles and complexity from your development of a modern front end Single Page Application.

Speed up client side end to end and integration tests

Instead of taking the time to setup mocking infrastructure on your front end you can simply record 3rd party calls your e2e testsuite makes and then mock them out during future test runs.  This allows you to avoid the complexity of testing a fully integrated application.  It makes your test suite less brittle and has the potential to speed up test runs tremendously.

How does it work?

Prism works by adding a middleware for the grunt-contrib-connect plugin.  It operates in much the same manner as grunt-connect-proxy, in fact by default it works the exact same way and lets you proxy traffic through your development connect server.

While in record mode you perform all the actions that trigger requests to your backend that you would like to record responses for. In record mode prism acts as proxy, but with the added capability of recording the proxied response. Prism will capture the request URL, including query parameters, content type, HTTP response status, and the data itself.  If the response type happens to be JSON then it will pretty print it in the response file for easier inspection.  For any other content-type it will fallback to a string.

An example response file in prism-sample-project:

./mocks/serve/6654ad4d1d494222ce02c656386e6955575c17ed.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "requestUrl": "/api/users",
  "contentType": "application/json; charset=utf-8",
  "statusCode": 200,
  "data": [
    {
      "user": "john",
      "fave_genre": "science fiction",
      "last_book_purchased": "the light of other days"
    },
    {
      "user": "genevieve",
      "fave_genre": "fantasy",
      "last_book_purchased": "game of thrones: a dance with dragons"
    },
    {
      "user": "zach",
      "fave_genre": "non-fiction",
      "last_book_purchased": "freakonomics"
    }
  ]
}

The filename is a SHA1 hash of the request URL in order to [almost] guarantee a unique filename for easy lookup in the future. After recording some responses you can switch to mock prism mode. When you launch your application and begin making the same requests you did before then instead of proxying your request, prism will intercept it, hash the request URL, and attempt to find a matching response in the appropriate directory.

If a response file can't be found then a 404 will be returned.

How do I use it in development?

The project homepage discusses pre-requisites and configuration in detail, but I'll summarize below. You must be using the grunt-contrib-connect plugin. If you use the Yeoman Angular.js generator (generator-angular) then this has already been done for you. Install the latest grunt-connect-prism package from NPM

npm install grunt-connect-prism --save-dev

Add the middleware to the appropriate target in your Gruntfile.js connect configuration section.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    connect: {
      options: {
        port: 9000,
        // Change this to '0.0.0.0' to access the server from outside.
        hostname: 'localhost',
        livereload: 35729
      },
      livereload: {
        options: {
          open: true,
          middleware: function(connect) {
            return [
              require('grunt-connect-prism/lib/events').handleRequest,
              connect.static('.tmp'),
              connect().use(
                '/bower_components',
                connect.static('./bower_components')
              ),
              connect.static(appConfig.app)
            ];
          }
        }
      },
...
   }

Next create a prism configuration object. You must specify a context of your server that prism will listen for requests on. Ex) http://localhost:9000/api/ would be the context of /api. You must specify the hostname, port, scheme configuration of where this resource is actually located. This constitutes the minimum configuration required to get up and running. Below is taken from the prism-sample-project. For a full example see that projects Gruntfile.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
prism: {
  options: {
    mode: 'proxy', /* optional */
    mocksPath: './mocks', /* optional */
    context: '/api',
    host: 'localhost',
    port: 9090, /* optional */
    https: false /* optional */
  },
  serve: {
    options: {}
  },
  e2e: {
    options: {}
  }
}

Inject prism into your serve call. This is a modified version of what the yeoman generator-angular creates for you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
grunt.registerTask('serve', 'Compile then start a connect web server', function(prismMode) {
 
  var prismTask = 'prism:serve';
 
  if (prismMode) {
    prismTask = prismTask + ':' + prismMode;
  }
 
  grunt.task.run([
    'clean:server',
    'wiredep',
    'concurrent:server',
    'autoprefixer',
    'express:api', /* my example backend server running on port 9090 */
    prismTask,
    'connect:livereload',
    'watch'
  ]);
});

The prism task can be called like any other grunt plugin: {pluginName}:{target}. Prism has an extra argument called "mode". This optional argument allows you to specify the prism mode without having to reconfigure the prism configuration in the Gruntfile.js each time. In the case of the above example, when you run `grunt serve` it will run the prism:serve target by default. If you have not configured this prism target's mode then it will default to proxy.

grunt serve

To enter a different mode then simply pass in the appropriate mode value when you call grunt serve.

grunt serve:record
grunt serve:mock

How do I use it with end to end testing?

Using prism for end to end testing involves much the same configuration as for development. You must add the middleware to the connect target you're using in e2e testing (i.e. connect:test) then call the prism task when you execute your e2e tests.

For this example I'm using protractor, grunt-protractor-runner (installed with prism-sample-project), and the standalone selenium server to run my e2e tests for my Angular.js project. I created a custom task to launch my tests with grunt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
grunt.registerTask('e2e', 'Run end to end tests', function(prismMode) {
  var prismTask = 'prism:e2e';
 
  if (prismMode) {
    prismTask = prismTask + ':' + prismMode;
  } else {
    prismTask = prismTask + ':mock';
  }
 
  // start the backend API if we're in record or proxy mode. this is probably
  // not applicable if you don't launch your backend server with grunt
  if (prismMode === 'record' || prismMode === 'proxy') {
    grunt.task.run(['express:api']);
  }
 
  grunt.task.run([
    'clean:server',
    'wiredep',
    'concurrent:server',
    'autoprefixer',
    prismTask,
    'connect:test',
    'protractor:e2e'
  ]);
});

The e2e task is configured to mock responses when you run `grunt e2e`.

grunt e2e

In order to record responses, or simply just let your e2e tests proxy to a real server then you can pass the prism mode into the e2e task in the same fashion as with the grunt serve task

grunt e2e:record
grunt e2e:proxy

Feedback

I hope that this blog post in conjunction with the README's of the plugin and sample project will provide you with enough information to get started with prism. Please see the grunt-connect-prism README.md for more information on the plugin and the prism-sample-project for a working example.

This is my first released open source and Node.js project. I would love feedback of any kind (pull requests, ideas, bug reports, critisicms, etc). Thanks!