grunt-connect-apimock

1.1.1 • Public • Published

grunt-connect-apimock

A middleware for the grunt-contrib-connect plugin that mocks a REST api with json-files from the filesystem. Makes it easy to develop and test your client code independent of the server.

The mocked api consistst of a number of json-files in a directory structure that represents the api.

E.g. with this configuration {url:'/myApp/api/', dir:'mymockdirectory'}, then apimock works like this:

GET /myApp/api/users uses the file mymockdirectory/users.json

POST /myApp/api/users uses the file mymockdirectory/users_post.json

GET /myApp/api/users/1 uses the file mymockdirectory/users/1.json

PUT /myApp/api/users/1 uses the file mymockdirectory/users/1_put.json

DELETE /myApp/api/users/1 uses the file mymockdirectory/users/1_delete.json

The format of the json-files can be in a simple or an advanced format. When using the simple format, the file content will be returned as the body of the response and http-status 200. When using the advanced format, it is possible to specify different responses and different http-status depending on the request parameters, body parameters, request headers or cookies of the request.

Getting Started

This plugin requires Grunt.

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-connect-apimock --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks('grunt-connect-apimock');

Configuration

E.g. I have a REST-api on the url:s /myApp/api/users, /myApp/api/products etc. And I want to mock this api with json-files in the directories mymockdirectory/users, mymockdirectory/products.

Configuring the "connect" task to use apimock

In your project's Gruntfile, add a section named apimock to your existing connect definition. And add the middleware call from the connect option middleware hook.

grunt.initConfig({
    connect: {
      options: {
            port: 8000,
            hostname: 'localhost',
            middleware: function (connect) {
                var middlewares = [];
                //add the apimock middleware to connect
                middlewares.push(require('grunt-connect-apimock/lib/apimock').mockRequest);
                return middlewares;
            }
      },
      apimock: {
        //apimock configuration
        url: '/myApp/api/',
        dir: 'mymockdirectory'
      }
    }

  });

Adding the configureApimock task to the serve task

For the serve task, add the configureApimock task before the connect task.

grunt.registerTask('serve', ['configureApimock', 'connect', 'watch']);

For multi-server configuration, see that section below.

apimock config parameters

apimock

Type: object or array of objects

An object containing the config of the apimock. See below. Can also be an array of objects if you want to mock different url:s to separate directories. E.g.

apimock: [
  {url: '/api1/', dir: 'test/api1'},
  {url: '/api2/', dir: 'test/api2', delay: 500}
]

apimock.url

Type: String

Required: yes

The beginning of the url for your REST-api that you want to mock.

apimock.dir

Type: String

Required: yes

The directorypath where your json-files for the apimock is located. The location is relative to the Gruntfile.js.

apimock.delay

Type: Number

Required: no

Default value: 0

The base delay for all requests to this url, before the mock will respond. In milliseconds.

json-file format

The json-files can be written in a simple or an advanced format.

Use the simple format if it is ok to get the same response body and HTTP-status 200 for any request data.

If you need to get different responses or HTTP-status depending on the request parameters, the request body, the request headers or cookies. Then use the advanced format.

Simple format

This is simple. The content of the file will be returned as the body of the response. With HTTP-status 200.

Advanced format

The apimock will switch to advanced format if the json object in the file has the variable "responses" or/and the variable "defaultResponse" on the root level that is != undefined. If none of the variables are defined. Then the content is considered as simple format.

defaultResponse

Type: Object

Required: yes

The default response that will be retured if none of the requests in the responses array matches.

defaultResponse.status

Type: Number

Required: no

Default value: 200

The HTTP-status.

defaultResponse.body

Type: Object

Required: yes

The response body.

defaultResponse.delay

Type: Number

Required: no

Default value: 0

The delay in milliseconds before the mock will respond.

responses

Type: Array

Required: no

An array of objects that contains the required request and the response that will be returned.

responses.request

Type: Object

Required: yes

Describing the matching criteria.

responses.request.parameters

Type: Object

Required: no

Names and values of the request parametes that needs to be matched for this response.

responses.request.body

Type: Object

Required: no

Names and values of the request body parametes that needs to be matched for this response.

responses.request.headers

Type: Object

Required: no

Names and values of the request headers parametes that needs to be matched for this response.

responses.request.cookies

Type: Object

Required: no

Names and values of the request cookies that needs to be matched for this response.

responses.response

Type: Object

Required: yes

Describing the response that will be retured if the request matches.

responses.response.status

Type: Number

Required: no

Default value: 200

The HTTP-status.

responses.response.body

Type: Object

Required: yes

The response body.

responses.response.delay

Type: Number

Required: no

Default value: 0

The delay in milliseconds before the mock will respond.

Examples

Different responses depending on the request parameters:

{
  "responses":[
    {
      "request":{
        "parameters":{
          "foo":"bar",
          "bar":"foo"
        }
      },
      "response":{
        "status":401,
        "body":{
          "message":"Two parameters matches"
        }
      }
    },
    {
      "request":{
        "parameters":{
          "foo":"bar"
        }
      },
      "response":{
        "status":402,
        "body":{
          "message":"One parameter matches"
        }
      }
    }
  ],
  "defaultResponse":{
    "status":201,
    "body":{
      "message":"Nothing matches. Default response"
    }
  }
}

Different responses depending on the request body:

{
  "responses":[
    {
      "request":{
        "body":{
          "user":{"firstname":"Luke", "lastname":"Skywalker"}
        }
      },
      "response":{
        "status":403,
        "body":{
          "message":"Two body parameters matches"
        }
      }
    },
    {
      "request":{
        "body":{
          "foo":"bar"
        }
      },
      "response":{
        "status":404,
        "body":{
          "message":"One body parameter matches"
        }
      }
    }
  ],
  "defaultResponse":{
    "status":201,
    "body":{
      "message":"Nothing matches. Default response"
    }
  }
}

A combination of request parameter and request body

{
  "responses":[
    {
      "request":{
        "parameters":{
          "foo":"bar"
        },
        "body":{
          "bar":"foo"
        }
      },
      "response":{
        "status":400,
        "body":{
          "message":"Both parameter and body matches"
        }
      }
    }
  ],
  "defaultResponse":{
    "status":201,
    "body":{
      "message":"Nothing matches. Default response"
    }
  }
}

Different responses depending on the request headers:

{
  "responses":[
    {
      "request":{
        "headers":{
          "header1":"one",
          "header2":"two"
        }
      },
      "response":{
        "status":401,
        "body":{
          "message":"When the headers header1=one and header2=two"
        }
      }
    }
  ],
  "defaultResponse":{
    "status":201,
    "body":{
      "message":"Nothing matches. Default response"
    }
  }
}

Different responses depending on the request cookies:

{
  "responses":[
    {
      "request":{
        "cookies":{
          "foo":"foo"
        }
      },
      "response":{
        "status":400,
        "body":{
          "message":"When cookie foo=foo"
        }
      }
    }
  ],
  "defaultResponse":{
    "status":201,
      "body":{
        "message":"Nothing matches. Default response"
      }
  }
}

Delaying a response:

{
  "responses":[
    {
      "request":{
        "parameters":{
          "foo":"foo"
        },
      },
      "response":{
        "status":200,
        "body":{
          "message":"Delayed 500 milliseconds"
        },
        "delay": 500
      }
    }
  ],
  "defaultResponse":{
    "status":200,
      "body":{
        "message":"Delayed 1000 milliseconds"
      },
      "delay": 1000
  }
}

For more examples see the tests in test/

Multi-server configuration

grunt-contrib-connect multi-server configuration is supported. You can make a config of apimock that is common to all server configurations. Or make a config that is specific to one server configuration.

In this example grunt serve will listen to port 8000 and serve api files from mymockdirectory.

grunt serve2 will listen to port 8080 and serve api files from mymockdirectory.

grunt serve3 will listen to port 8080 and serve api files from someOtherDirectory.

grunt.initConfig({
    connect: {
      options: {
            port: 8000,
            hostname: 'localhost',
            middleware: function (connect) {
                var middlewares = [];
                //add the apimock middleware to connect
                middlewares.push(require('grunt-connect-apimock/lib/apimock').mockRequest);
                return middlewares;
            }
      },
      apimock: {
        //apimock configuration
        url: '/myApp/api/',
        dir: 'mymockdirectory'
      },
      server1: {
          options:{
          }
      },
      server2: {
          options:{
            port: 8080
          }
      },
      server3: {
          apimock: {
            url: '/myApp/api/',
            dir: 'someOtherDirectory'
          },
          options:{
            port: 8080
          }
      }
    }
});

grunt.registerTask('serve', ['configureApimock', 'connect:server1', 'watch']);
grunt.registerTask('serve2', ['configureApimock', 'connect:server2', 'watch']);
grunt.registerTask('serve3', ['configureApimock:server3', 'connect:server3', 'watch']);

Contributing

In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.

Release History

  • 1.1.1 Fix timeout body parsing. Fix tests after output from connect changed.
  • 1.1.0 Added feature to delay the response. Changed test framework.
  • 1.0.0 Celebrating 1 year since the first release by bumping the version to 1.0.0. No new features since 0.3.3
  • 0.3.3 Check Content-Type before parsing request body
  • 0.3.2 Make it possible to use newer grunt
  • 0.3.1 Changed statusCode when a json-file isn't found
  • 0.3.0 Added feature to mock different url:s to separate directorys
  • 0.2.0 Added feature for selecting response depending on request headers or cookies
  • 0.1.0 Initial release

License

Copyright (c) 2016 Lars Johansson. Licensed under the MIT license.

Package Sidebar

Install

npm i grunt-connect-apimock

Weekly Downloads

83

Version

1.1.1

License

MIT

Unpacked Size

76.2 kB

Total Files

53

Last publish

Collaborators

  • ljohansson