rest-client-tester

0.0.11 • Public • Published

#Rest-Client-Tester

Helps you to check the stability of one api, by testing it constantly.


Example.

enter image description here

##Answering some questions

###Why? Sometimes we become strongly dependent of some apis, that must follow some contract in order to our systems to work. With this solution, you can be warned when a system is out or when someone breaks the contract.

###How?

The workflow is basically:

1. Update Request
2. Do Rest Request
3. Assert Response
4. Collect Statistics
5. Repeat

##Real live Example

  1. Clone this project: Rest-Client-Tester-Example
  2. And run:
cd rest-client-tester-example
npm install
node index.js

After that just follow what application ask you to.


##Examples

###Simple Request

  • Test if API is answering status code 200.
  • Test if id that was sent is received.

####JS FILE

	function Endpoint(){
	
	var endpoint = require("rest-client-tester/endpoint.js")();
	var assert = require("rest-client-tester/util/assert");
	
	var id = 2;
	endpoint.retry.retryEach(500);
	
	endpoint
		.request
			.setUrl("http://demo3840477.mockable.io/person/search/id/")
			.setUrlSuffix(id)
			.setRequestType("GET")
			.setTimeOut(4000)
			.addHeader("Content-Type", "application/json");
		

	endpoint.response
		.checkResponse(function(request, response, promise) 
	      {
			assert.assertEquals(200, response.statusCode, "Status code is unespected.");
			assert.assertType(response.body, 'object' , 'Response should be an object');
			assert.assertEquals(response.body.id, request.urlSuffix, "Should return the id that was send.");
			promise.resolve();
	}
 );
	
	return endpoint;
}

module.exports = Endpoint;

Simple Request + Update Each

Imagine that now you want to check each ID that is valid. You could something like: Each request will increase +1 to id value.

endpoint.request
	.updateRequest(function(request, response, promise) {

        if(!endpoint.isRequestNumber(0)) {
	        console.log("Is not first request, so update!");
            id++;
        }
	   	request.setUrlSuffix(id);
			//always required to release promise!
			promise.resolve(request);
		}
	);

Endpoints that depends on another

Thanks to Promise, this application will wait until you inform it to continue.

You can see Promise in Response.checkResponse() and Request.updateRequest() methods.

//in both cases, timeOut is optional and have a default value.
var timeOutMs = 5000;

endpoint.response
   .checkResponse(function(request, response, promise) { 
	    //do stuff... like async calls.
	    promise.resolve(); //now you can execute application!
   }, timeOutMs
);

endpoint.request
	.updateRequest(function(request, response, promise) { 
		//do stuff... like async calls.
		promise.resolve(); //now you can execute application!
	}, timeOutMs
);

This means, that you can inject an endpoint to collect data, or validate if response is valid!

  
endpoint.response
	.checkResponse(function(request, response, promise) {
	
		assert.assertEquals(200, response.statusCode, "Status code is unespected.");
		//assert data from other endpoint
		assertStatusCode(response, promise);
	}
);

function assertStatusCode(response, promise) {
  	var statusEnd = require("./statusCustomer")().setId(id);
	
	statusEnd.doRequestAndAsserts().then(
		function(){
			//statusEnd did request and asserts are ok.
			assert.assertEquals("AUTHORIZED",
				 statusEnd.response.body.status, 
				 "This user should be already authorized.");
				
			//now that I've confirmed status, you can retry.
			promise.resolve();					
		}, 
		function(err){
			console.log('Oops, some assert was triggered!');
			promise.reject(err);
		}).catch(function(err) {
			console.log('Something unexpected happened');
			promise.reject(err);
		}
	);
}	

Collecting data

After executing and asserting, you can collect statistics, as you wish.

endpoint.collectStatistics = function(){

		/*
		examples: 
		endpoint.response.isValid;
		endpoint.response.error;
		endpoint.response.statusCode;
		endpoint.request.urlSuffix;
		endpoint.request.body;
		endpoint.response.duration.getMs();
		endpoint.response.duration.getWhenStarted();
		endpoint.retry.getRetries()
		ajax.post(data);
		file.write(data);
		mongodb.save(data);
		*/
	}	

Complete example

Following all these definitions, you'll have a code like this:

/**
	For this API, I've created only ids: 2 e 5.
	2 is valid and 5 has wrong data.

*/
function Endpoint(){
	
	var endpoint = require("rest-client-tester/endpoint.js")();
	var assert = require("rest-client-tester/util/assert");
	var logger = require("rest-client-tester/util/logger");

	endpoint.retry.retryEach(500);
	
	endpoint.response.config.checkResponseTimeOutMs = 10000;

	endpoint
		.request
			.setUrl("http://demo3840477.mockable.io/person/older")
			.setRequestType("GET")
			.setTimeOut(5000);

	endpoint.request
		.updateRequest(function(request, response, promise) {
            logger.debug("Updating search-older request");
			promise.resolve(request);
		}, 5000
	);

	
	var personEndPoint = require("./search-person")();

	endpoint.response
		.checkResponse(function(request, response, promise) {
			//search-older
			assert.assertEquals(200, response.statusCode, "Status code is unespected.");
			assert.assertType(response.body, 'object' , 'Response should be an object');
			assert.assertNotNull(parseInt(response.body.id), "Should return the oldest person.");
			
			personEndPoint.setId(parseInt(response.body.id))
				.doRequestAndAsserts().then(
					function(){
						//console.log('The person is valid!');
						assert.assertEquals("John P.", personEndPoint.response.body.name, "Expected that John was the older");
						promise.resolve();					
					}, 
					function(err){
						console.log('Is not ok! the id is invalid! %o', err);
						err.log();
						promise.reject(err);
					}).catch(function(err) {
						promise.reject(require("rest-client-tester/util/errorholder")().setError("Uncaught error while searching user", exc));
					}
			);
		}, 10000
	);

	
	return endpoint;

}

module.exports = Endpoint;

But how can I use it?

Its simple. Just require the main class and inform the folder that contain your endpoints.

// init.js
var tester = require("rest-client-tester");
tester.setFolder("./my-services");
tester.init();

And after that, execute this file:

node init.js

This example is expecting the following structure:

my-project/
	node_modules/
	my-services/
		customer-services/
			searchEndpoint.js 
			createEndpoint.js
		address-services/	
			searchEndpoint.js 
			createEndpoint.js

Debugging

In order to debug, you can add the following lines to your init.js file.

//show logs - except request/response
require("rest-client-tester/util/logger").isDebugActive = true;
//show request and response.
require("rest-client-tester/util/logger").showDebugRequest = true;

Asserting

I've create a simple lib to do asserts in Response.checkResponse():

	var assert = require("rest-client-tester/util/assert");
	assert.assertEquals(expected, received, message);
	assert.assertNotEquals(expected, received, message);
	assert.assertTrue(received, message);
	assert.assertFalse(received, message)
	assert.assertNull(received, message);
	assert.assertNotNull(received, message);
	assertType(received, type, message); // typeof received

##Docs Some explanation of each main objects.


###Endpoint Endpoint is the main class, that deal with request, response and retries. It contains the following structure:

{ 
  request: Request,
  response: Response,
  retry: Retry,
  event: { },
  doRequest: [Function],
  executeAsserts: [Function],
  doRequestAndAsserts: [Function],
  collectStatistics: [Function],
  isRequestNumber: [Function],
  success: [Function],
  fail: [Function],
  isEndPoint: true,
  toString: [Function]
}

[object] Endpoint.Request

Contains all information related to the request itself. (url, timeout, body, headers, updateRequest). (More info below)

####[object] Endpoint.Response Deals with the response of rest call ( body, headers, duration and asserts) (More info below)

####[object] Endpoint.Retry Deal with the ability of retrying the execution. (retry qty, can execute) (More info below)

####[object/map] Endpoint.Event Give you some events options. Nowadays its only "disable in case of fail or success".

endpoint.event.stopWhen.hasSucceed = true;
endpoint.event.stopWhen.hasFailed = true;

####[function] Promise Endpoint.doRequest()

Execute the request. Returns a Promise.

endpoint.doRequest().then(function(response){
   //endpoint.response can be used too.
}, function(error){
	//maybe timeout
}).catch(function(error){
	//something is terrible wrong - maybe a class.
});

####[function] Promise Endpoint.executeAsserts() Execute the asserts you've created. Normally you won't use this method (check doRequestAndAsserts()).

endpoint.executeAsserts().then(function(){
   //its a valid response!
}, function(error){
	//some assert failed!
}).catch(function(error){
	//something is terrible wrong - maybe a class.
});

####[function] Promise Endpoint.doRequestAndAsserts() Execute request and asserts.

endpoint.doRequestAndAsserts().then(function(){
   //its really valid!
}, function(error){
	//some assert failed / timeout for example
}).catch(function(error){
	//something is terrible wrong - maybe a class.
});

####[function] Endpoint.collectStatistics() Function executed after the asserts were executed - regardless success or fail in asserts. Here you can warn someone, or put it in a db.

endpoint.collectStatistics = function() {
	endpoint.response.isValid;
	endpoint.response.error;
	endpoint.response.statusCode;
	endpoint.request.urlSuffix;
	endpoint.request.body;
	endpoint.response.duration.getMs();
	endpoint.response.duration.getWhenStarted();
	endpoint.retry.getRetries()
	//sendit.
}

####[function] boolean Endpoint.isRequestNumber(int reqNumber) Informs if the actual execution is equal to the expected number. You can use it to update request when reach request 20, or dont update if is the first.

if(endpoint.isRequestNumber(5)){
   console.log("Doing something different");
}

####[function] String Endpoint.toString (optional to edit) Prepare the message you want to display in console. Default value example:

[13:47:05] - [#7] [GET] http://demo3840477.mockable.io/person/older  time: [32.9ms] statusCode: [200]

Internal attributes

This one are internal, and you don't need to use.

  1. success: check if must reexecute and set some information.
  2. fail: check if must reexecute and set some information
  3. isEndPoint: flag used to identify if is a valid class.

###Request Deals with the information of Request. It contains the following structure:

{ 
  url: 'http://demo3840477.mockable.io/person/search/id/',  
  urlSuffix: 2,
  type: 'GET',
  headers: {},
  body: null,
  timeOut: 4000,
  config: { 
	  updateRequestTimeOutMs: 5000,
	  updateNextRequest: true 
  },
  setUpdateRequestTimeOut: [Function],
  setUrl: [Function],
  setUrlSuffix: [Function],
  setRequestType: [Function],
  setTimeOut: [Function],
  setBody: [Function],
  addHeader: [Function],
  getHeader: [Function],
  asJson: [Function],
  updateRequest: [Function],
  update: [Function],
  toString: [Function],
  isRequestObject: 'yes' 
}

The biggest part of these methods are in order to collect information as well.

Special Methods

[Function] Request.setUpdateRequestTimeOut(int timeMs)

In order to keep the execution working, this application wait a time for you to update your request. If it take longer than that, it will conclude that something is wrong. So it will show:

Have you forgot to put promise.resolve() in your update method? Or do you need more time executing update? Use request.setUpdateRequestTimeOut(ms).

In order to make increate the time, you can use this function.

[Function] Request.updateRequest(function)

Set the function that will update your request. It have 3 parameters.

  1. Request
  2. Response: It can be null - if is the first call.
  3. Promise: Always execute Promise.resolve() after all - that allows your application to keep executing.
endpoint.request
	.updateRequest(function(request, response, promise) {
		//you can use endpoint.response or response
        if(endpoint.response.body.id > 1) {
		    id++;
        }
       	//you can use endpoint.request or request
		request.setUrlSuffix(id);
		//always resolve
		promise.resolve(request);
	}
);

[Function] Promise Request.update()

Execute your update function. It will not update in case that the flag Request.config.updateNextRequest is false.

endpoint.request.update().then(function(){
    //its updated!
}, function(error){
	//something went wrong!
}).catch(function(error){
	//something is terrible wrong - maybe a class.
});

[Function] Promise Request.toString()

Transform in string to be used by Endpoint.toString(). You can override it as you wish.


###Response Deals with the information of Response. It contains the following structure:

{ 
  config: { 
	  checkResponseTimeOutMs: 5000 
  },
  statusCode: null,
  body: {},
  duration: Object
  headers: {},
  isValid: null,
  error: null,
  reset: [Function],
  setCheckResponseTimeOut: [Function],
  loadResponse: [Function],
  checkResponse: [Function],
  hasCheckResponse: [Function],
  check: [Function],
  toString: [Function] 
}

The biggest part of these methods are in order to collect information as well.

Special Methods

[Function] Request.setCheckResponseTimeOut(int timeMs)

In order to keep the execution working, this application wait a time for you to assert your response. If it take longer than that, it will conclude that something is wrong. So it will show:

Have you put promise.resolve() in your checkResponse method? Or do you need more time to execute this assert? In this case use Response.setCheckResponseTimeOut(ms).

[Function] Response.checkResponse(function)

Assert that your response is ok. It have 3 parameters.

  1. Request
  2. Response:
  3. Promise: Always execute Promise.resolve() after all - that allows your application to keep executing.

And you can still use endpoint.response | endpoint.request

endpoint.response
.checkResponse(function(request, response, promise) {
	assert.assertEquals(200, response.statusCode, "Status code is unespected.");
	assert.assertType(response.body, 'object' , 'Response should be an object');
		assert.assertEquals(parseInt(response.body.id), request.urlSuffix, "Should return the id that was send.");
			promise.resolve();
		}
	);

[Function] Promise Response.check()

Execute your checkResponse function.

endpoint.response.check().then(function(){
    //its valid!
}, function(error){
	//something went wrong!
}).catch(function(error){
	//something is terrible wrong - maybe a class.
});

Warning to all developers: This lib is still under construction!

It works, but it still able to change!

  1. Unit tests wasnt created yet.
  2. It was not tested with https requests.
  3. Still searching for scenarios that it didnt work. If you find, please let me know. (gabriel.scarvalho310@gmail.com)
  4. I've created this documentation in help to order people who got this lib before its final version.
  5. In a near future, it will have a screen that shows all the services running, like a jenkins panel. For updates, follow: https://twitter.com/jsRestTester.

Readme

Keywords

Package Sidebar

Install

npm i rest-client-tester

Weekly Downloads

12

Version

0.0.11

License

ISC

Last publish

Collaborators

  • gabrielsc310