By default the tool creates the mock server into the server
sub-folder under the project root.
The original setup is the following:
server/
├── api.js
├── config.js
├── config.yml
├── monitoring.js
├── package.json
├── Readme.md
└── server.js
Where
Readme.md
A short readme file about how to use the server.
server.js
The mock server itself.
config.yml
Configuration parameters of the mock server.
config.js
Helper module to load the configuration parameters.
package.json
Module dependencies of the server. By default this file contains all the required dependencies, but the package.json
file in the parent folder also contains them, so you do not need to install them in the server's folder, because it will access them from it parent's node_modules
folder.
You can extend this file, if you need additional modules installed to implement dynamic behavior. In this case you have changed this file, you have install the packages, so run the npm install
command in the server folder.
api.js
A boilerplate module to implement your own implementation functions. If you want to implement only a couple a functions, it is enough to define them in this module, and just refer to them. In case of more complex logic, you'd better create your own modules.
monitoring.js
A sample module, which demonstrates how an implementation should be written.
In a newly created API project the server is configured to work immediately. The default config.yml
looks like this:
# Use this environment by default,
# if server is started without the <env> parameter
useEnvironment: development
#useEnvironment: production
environments:
# This is the default configuration set
default:
documentRoot: .
port: 3007
restapiRoot: ..
remoteServices: []
# Override the default config parameters
# with values specific to the development environment
development:
port: 3007
documentRoot: ../webui
# A development environment with proxying
# the 'serviceUrlPrefix' requests to the local host
devProxy:
port: 3006
documentRoot: ../webui
remoteServices:
-
uri: /monitoring
active: true
host: localhost
port: 3007
-
uri: /*
active: true
host: localhost
port: 3008
# A second development environment with proxying the
# 'serviceUrlPrefix' requests also to the local host
# but with some exceptions.
devProxyWithExceptions:
port: 3006
documentRoot: ../webui
proxyException:
active: true
urlPrefixList:
- /monitoring/isAlive
- /Flight/legs/.*/closeLeg
remoteServices:
-
uri: /*
active: true
host: localhost
port: 3008
# production environment specific values
production:
port: 3008
documentRoot: ../webui/build/crm-api/production
In general the configuration file can contain any property, but should contain at leas two mandatory properties. These are: environments
and useEnvironment
.
The configuration parameters are grouped into environments which are described under the environments
array propery. Each environment is identified by its name and describe a specific server configuration. The configuration file must define at least one environment, that is the default.
The useEnvironment
tells the server that which environment should be used by default, if it was not specified explicitly when the it is started.
An environment usually has the following configuration properties:
documentRoot: (string | Array) Defines the path to the folder, which is used as the document root to the static content provided by the server. This content can be anything: static HTML pages, Fontend JavaScript application (Backbone, ExtJs, etc.), or anything. This parameter can be an individual string or an array of strings. For example: ../webui
port:
(integer)
The port where the server is listening.
For example: 3007
restapiRoot:
(string)
Path of the project root folder. server needs this in order to be able to access to the service descriptions and mock data files.
For example: ..
remoteServices:
(Array)
An array of server-side forwarding rules used by the proxy middleware. If the proxy middleware is used, it iterates through this array, and try to match the requested URI with the uri
property of each item of this array. Each rule contains the following properties: active, uri, host and port respectively. These properties are described below. The items are matched in order, and the first matching uri
will be used. If none of the uri
is matching, then no forwarding happens.
uri:
(boolean)
A regular expression which fully or partially matches an existing service defined under the services
folder. For example: /monitoring/isAlive
identifies exactly one service. /monitoring/*
stands for any service starting with /monitoring/
. /*
means all services.
active:
(boolean)
If true, the server acts as a proxy server, and forwards the service requests to a remote host.
For example: false
host:
(string)
The host name of the remote host. Used only if the server is in proxy mode with the given service (uri
matches and active: true
).
For example: localhost
port:
(integer)
The port of remote host. Used only if the server is in proxy mode with the given service (uri
matches and active: true
).
For example: 3008
proxyException:
(Array)
Defines exceptions of remote services which should NOT be proxied.
active:
(boolean)
If true, the exception rules are active. Default value is: false.
For example: true
urlPrefixList:
(Array)
Provides uri
patterns to match against requests, which should not by proxied.
Example items: /monitoring/isAlive
, /Flight/legs/.*/closeLeg
.
Beside the parameters listed above, you can add further ones to the config file, if you want to extend the functionalities of the server.
To start the mock server with the default configuration, execute the following command:
$ node server/server.js
This will start a web server, which will listen on the localhost, and the port specified in the config.yml
file (3007 by default).
After starting the server, you can can try it with a browser, or the curl
command line tool:
$ curl http://localhost:3007/rest/monitoring/isAlive
true
If you want to start the server with an other configuration (devProxy
for example), define it as a parameter in the following format:
$ node server/server.js devProxy
register service GET /monitoring/isAlive
/monitoring/isAlive
register service GET /customers
/customers
register service POST /customers
/customers
Express server listening on port 3006 in devProxy mode
As you can see, the server is listening now on port 3006, and proxying the HTTP requests to the localhost:3008
.
The following code fragment shows how the middle-ware is configured for the mock server:
// Configure the middle-wares
server.configure( function() {
server.use( proxy(servicesConfig.serviceUrlPrefix, config.remoteServices) );
server.use( express.bodyParser() );
server.use( express.methodOverride() );
server.use( express.cookieParser() );
server.use( express.session( {secret: 'keyboard cat'} ) );
server.use( server.router );
server.use( '/data', express.static( __dirname + '/' + '../data' ) );
server.use( '/docs', express.static( __dirname + '/' + '../docs' ) );
server.use( '/services', express.static( __dirname + '/../services' ) );
server.use( express.static( __dirname + '/' + config.documentRoot ) );
});
The order of processing is the following:
server.use(proxy(servicesConfig.serviceUrlPrefix, config.remoteServices));
config.remoteServices
array. If any one of them is matching, and the proxying is activated with that matching uri
, then forwards the request to the remoteService.host:remoteService.port
. In other words, every matching service call is proxied to the remote server.server.use(server.router);
server.router
, so in this phase the service are provided on the normal way, if the proxy is not enabled.server.use('/data', express.static(__dirname + '/' + '../data'));
<project-root>/data
folder is provided by this middle-ware. You can place additional data files into this folder. server.use('/docs', express.static(__dirname + '/' + '../docs'));
<project-root>/docs
folder is provided by this middle-ware. Actually this is the HTML format documentation, generated by the rest-tool docs --update
command. So you can read it off-line and on-line as well, provided by the mock server itself.server.use('/services', express.static(__dirname + '/../services'));
<project-root>/services
folder is provided by this middle-ware. These are the folders that describe the services, and contain the additional mock data and other files. In normal cases you do not need this, however you might want to write special service modules, that might want to access these files through HTTP requests.server.use(express.static(__dirname + '/' + config.documentRoot));
documentRoot
config parameter. Typically it points to the source, or distribution folder of the the front-end application under development.As it is described in the previous section, the HTTP middle-ware is configured to process the incoming request in the following order:
service.yml
files.docs
, data
, etc.The the mock server is providing generated documentation by default. You also can configure a so called document root folder, for your web UI.
The next setup is typical for a UI development project:
documentRoot
configuration parameter.In the service.yml
file, every method's request
object can have an optional property, which can identify an implementation function in the following format: <module>.<function>
.
In order to use this feature, you must have a module written in JavaScript placed into the server
folder named <module>.js
, which contains an exported function with the name of <function>
. For example the following file is named monitoring.js
and contains the implementation of the response logic which will be called when the referring method is activated:
function isAlive( request, response, serviceDescriptor )
{
response.header( 'Content-Type', 'application/json' );
response.header( 'X-Application-API-Version', 'v0.0.0' );
response.write( 'true' );
response.end( '\n' );
};
exports.isAlive = isAlive;
As you can see, the function gets all the request parameters, as well as the response object, which is used to compose the response.
In order to be able to behave the expected way, the function gets a third parameter (serviceDescriptor
), which holds all the data found in the corresponding service.yml
file. This object also provides methods to access to the mock files situated beside the service descriptor.
The mock server implementation is built on top of the express.js web framework. In order to learn more about how to use the request
and response
parameters, visit its API documentation pages.
Note that you have to export those functions you would like to use externally. This is done by the
exports.isAlive = isAlive;
line of the code fragment above.You must add a line to the
server.js
which tells the server to load this module when starts. In case of the previous example the following line must be added:
var monitoring = require('./monitoring.js');
If you are not familiar with how to create modules, and how to use exports
, etc. read the Node.js documentation.
The rest-tool
creates the following empty extension module with the new project that is called api.js
.
/**
* Implementation of method calls defined in `service.yml` files
* This file is generated by the rest-tool tool.
*/
var services = require('rest-tool-common').services;
var server = require('./server.js');
//=============================================================================
// Put your mock method implementations here
In case you only want to add a couple of simple function, and do not want to bother with creating ad require
-ing your own module, you should just simple define these functions in this api.js
(export the functions), and refer to them from the service.yml
files, with the implementation
property. This server is loading this api.js
by default, so you do not need to modify that.
By default rest-tool returns with only one response, described in the service.yml that is:
name: OK
statusCode: 200
Each method must have at least one OK
response. All the other codes listed under the responses provide documentation purposes by default.
In order to decide which (other) code the server should response you have to built some logic into the server, so you have to make a module inside the server folder, and implement the function that the given method will call. You can refer to this method with the 'implementation' property of each method in the service.yml
file.
Also, you have to require
the newly created module in the server/server.js
file.
Below I will explain how can you respond with 400
:
After the creation of a new project, the rest-tool automatically creates a service, that is called monitoring/isAlive
. You can find its descriptor in the services/monitoring/isAlive/service.yml
.
This file contains a GET method, and that has an implementation, that is:
implementation: monitoring.isAlive
So there is an implementation module, under the server folder, that is: monitoring.js
.
function isAlive( request, response, serviceDescriptor )
{
response.header( 'Content-Type', 'application/json' );
response.header( 'X-Application-API-Version', 'v0.0.0' );
response.write( 'true' );
response.end( '\n' );
};
exports.isAlive = isAlive;
So, if the server is running, you will get the response of true
is you call this service:
$ curl http://localhost:3007/rest/monitoring/isAlive
true
If you want to response a different status-code (400 for example), replace the body of the isAlive
function with the following code:
function isAlive( request, response, serviceDescriptor )
{
response.status(400).send('Bad Request');
};
Restart the server, and call again the service. The result will be the following:
$ curl http://localhost:3007/rest/monitoring/isAlive
Bad Request
To see also the code, call the curl
with -v
:
$ curl http://localhost:3007/rest/monitoring/isAlive -v
* About to connect() to localhost port 3007 (#0)
* Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 3007 (#0)
> GET /rest/monitoring/isAlive HTTP/1.1
> User-Agent: curl/7.27.0
> Host: localhost:3007
> Accept: */*
>
* additional stuff not fine transfer.c:1037: 0 0
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 400 Bad Request
< X-Powered-By: Express
< Vary: Accept-Encoding
< Content-Type: text/html; charset=utf-8
< Content-Length: 11
< X-Response-Time: 1ms
< Set-Cookie: connect.sid=s%3As8tJdvyopZnjRndqPrh1U_Qh.N8Eln3hIcweFei1r6gkVeSr7f%2F3iKV3gxFI4Y44P8qo; Path=/; HttpOnly
< Date: Sat, 20 Dec 2014 14:54:30 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
Bad Request* Closing connection #0
As you can see, the implementation function gets the whole service descriptor as its third parameter. So you can access to any proerty you have defined in the service.yml
.
It is very likely that your server implementation will be written in a different language, not in JavaScript, and developed by an other team.
However one of the advantages of using rest-tool is to let the development teams working parallel with each other, you have to integrate your front-end with the back-end, for several reasons, but the most obvious one is, to see how the two parts work together, and do bug-fixing.
In such situations you need your independent front-end environment as well as you should be able to connect to the real implementation instead of the mock server. For security reasons, in such cases you usually should deploy your front-end to the application server, that can be rather time consuming. This is the case, when the proxy comes into the picture. You can continue using your mock server as static content provider, to load your front-end application, but you can switch on its proxy function to forward the service calls to a remote server, that is the application server your front-end should be tested with.
In order to use this feature, create a configuration of the server (according to the The mock server configuration section) to enable the proxy function that forwards the requests to the test application server, and continue using the mock to provide its static content that you have been used so far for development. This way, you can connect to the real, or test application server without the long-lasting deployment process, and easily switch back and forth between the mock and the other back-end implementation.
Using an array of forwarding rules, it is possible to proxy different services toward differend servers. For example you can use the original mock server to provide the frontend code under development provided as static content directly by the mock server. Then you can also provide some basic REST services also by the mock server (/monitoring/isAlive
, etc.). At the same time you can add some rules to forward the REST calls to an other Node.js, PHP or JEE backend server. Moreover you can add an other proxy rule to forward REST calls to a third party messaging middleware (RabbitMQ, HornetQ, etc.).
You can individually enable/disable the forwarding of each service call, using the active
field in the configuration. This way, you can first use the mock services, until the final implementation gets ready to use. Then you can switch out to the real backend service one-by-one.
In some cases it is not easy to control the proxy-ing of individual services under development, meanwhile we want to forward all the other requests to a remote server.
For such cases you can use the proxyException
patterns. This is a different approach. Here you can allow the remote services in general, and add the exceptions one-by-one to the proxyException
list.