Mock server simulating Availity API rest services
- Intro
- Server Configuration
- Route Configuration
- Proxy Configuration
- Events
- Contributing
- Authors
- Disclaimer
- License
Develop web applications without heavy back-end services by running a simple Express http server which can deliver mock responses.
Responses can be JSON or other formats to simulate REST services. Access-Control HTTP Headers are set by default to allow CORS requests. Mock services are configured in the routes.json file.
This server can return other file types besides XML or JSON (PDFs, images, etc). The appropriate response headers will be automatically set for different file types. For a complete list of file types supported view the mime types here.
The default server configuration can be found in config.js. Pass a different configuration file to the Ekko server to override the defaults.
var path = require('path');
var Ekko = require('availity-ekko');
var configPath = path.join(__dirname, 'path/to/config.js');
var ekko = new Ekko(configPath);
ekko.start();
Ekko also supports overriding defaults using command line arguments (useful to setup different configurations in WebStorm). The CLI commands are equivalent to the config.js
object using dot notation. Using example configuration below, run node index.js --severs.web.port=8888
to override the web server port for development
mode.
{
development: {
...
servers: {
web: {
host: "0.0.0.0",
port: 9999 // --severs.web.port=8888
}
}
...
}
}
The routes.json
defines the mock responses for rest services. Below are some sample scenarios that should help you understand the configuration options.
The mock configuration supports deep nested introspection of JSON and multi-part form data when matching routes. See Example 6 below.
"v1/route1": {
"file": "example1.json" // match for GET|PUT|POST|DELETE
}
"v1/route2": {
"latency": 250, // latency in (ms)
"file": "example2.json", // match for all GET|PUT|POST|DELETE requests
"status": 201 // return status code 201
}
"v1/route3": {
"file": "example3.json", // match for GET|PUT|DELETE requests
"post": "example1.json" // match for POST requests
}
"v1/route4": {
"get": "example1.json", // match for all GET requests
"put": "example2.json", // match for all PUT requests
"post": "example3.json", // match for all POST requests
"delete": "example4.json" // match for all DELETE requests
}
"v1/route5": {
"file": "example1.json", // match for all POST|PUT|DELETE requests
"get": [
{
"file": "example2.json",
"status": 200, // default status code is 200
"params": { // match for GET /v1/router?a=1&b=2&c=3
"a": "1",
"b": "2",
"c": "3"
}
},
{
"file": "example3.json",
"params": { // match for GET /v1/router?a=1&a=2&a=3&a=4
"a": [1, 2, 3, 4]
}
},
{
"file": "example4.json",
"params": { // Regular expression configruation for matching params
"a": { // match for GET /v1/router?a=1 OR /v1/router?a=2 OR /v1/router?a=3
pattern: "1|2|3",
flags: "i" // Javascript regex flags to ignore case
}
}
},
]
}
"v1/route6": {
"file": "example1.json", // match for all GET|PUT|DELETE requests
"post": [
{
"file": "example2.json",
"params": { // match for POST with JSON payload {"a": 1}
"a": 1
}
},
{
"file": "example3.json",
"params": { // match for POST with JSON payload {a: {b: {c: "1"} } }
"a.b.c": 1 // config allows for nested attributes
}
},
{
"file": "example4.json",
"params": { // match for POST with JSON payload {a : {b: [0,1,2] } }
"a.b[2]": 2 // config allows for nested array attributes
}
}
]
},
<form action="/api/v1/users" method="post" enctype="multipart/form-data">
<p><input type="text" name="a" value="example">
<p><input type="file" name="b"> <!--the name of the file is used below to match and score the proper response -->
<p><button type="submit">Submit</button>
</for
"v1/route7": {
"file": "example1.json", // match for all GET|PUT|DELETE requests
"post": [
{
"file": "example2.json" // default response if none match below
},
{
"file": "example3.json",
"params": { // match for form submit where form fields a=1 and b="sample.pdf"
"a": 1,
"b": "sample.pdf"
}
},
{
"file": "example4.json",
"params": { // match for form submit where form fields a=2 and b="another.name.jpg"
"a": 2,
"b": "another.name.jpg"
}
}
]
}
"v1/route8": {
"file": "example1.json",
"get": [
{
"file": "example1.json",
"response": [
{
// match for first GET request to /v1/route8
"status": 202,
"file": "example1.json"
},
{
// match for second GET request to /v1/route8
"status": 201,
"file": "example2.json"
}
]
}
]
}
"v1/route10": {
"get": [
{
"file": "example1.json",
"response": [
{
"status": 202,
"file": "example1.json",
"repeat": 3
},
{
"status": 202,
"file": "example2.json"
},
{
"status": 202,
"file": "example3.json",
"repeat": 4
},
{
"status": 201,
"file": "example4.json"
}
]
}
]
}
"v1/route11": {
"file": "example1.json",
"get": [
{
"file": "example2.json",
"headers": { // match for GET with header pair b:2
"b": "2"
}
},
{
"file": "example3.json",
"headers": { // match for GET with header pair b:3
"c": "3"
}
}
]
}
"v1/route9": {
"url": "http://www.google.com"
}
You define Ekko server configurations in config.json
. Each configuration requires a host
. Other configuration options are outlined below. You must have a configuration called web
that is used to serve static files and the proxy server. An example configuration looks like this:
{
user: 'johndoe', // global set `RemoteUser` header across all proxy requests
servers: {
web: { // (required) server used for static resources
host: "0.0.0.0",
port: 9999
}
}
}
If you omit the port, or set it to 0
, Ekko will let the OS assign a random open port.
This allows you to run multiple servers without keeping track of all ports being used. (see Example 2)
servers: {
web: {
host: "0.0.0.0",
port: 0 // dynamic port
}
}
servers: {
web: {
host: "127.0.0.1",
port: 9999
},
api: {
host: "127.0.0.1",
port: 7777, // port number to proxied server
proxy: true, // defaults to false. when true the proxy is enabled
headers: {
"userid": "johndoe" // set custom header for proxy requests to this server
},
proxies:
[
{
context: "/api", // if url context matches the proxy is triggered for all routes
rewrite: { // (optional) allows url to be rewritten before forwarding request to a proxied server
from: "^/api", // convert /api/v1/ping
to: "" // to /v1/ping
}
}
]
}
}
servers: {
web: {
host: "127.0.0.1",
port: 9999
},
api: {
host: "127.0.0.1",
port: 7777,
proxy: true,
proxies:
[
{
context: "/api",
rewrite: {
from: "^/api",
to: ""
},
headers: {
"userid": "johndoe" // set custom header for proxy requests this context for this server
}
},
{
context: "/api2", // you can define multiple context's for a proxied server
rewrite: {
from: "^/api2",
to: "/v1"
}
}
]
}
}
servers: {
web: {
host: "127.0.0.1",
port: 9999
},
api: {
host: "127.0.0.1",
port: 7777,
proxy: true,
proxies:
[
{
context: "/api",
rewrite: {
from: "^/api",
to: ""
}
}
]
},
other: { // define more servers to proxy
host: "127.0.0.1",
port: 8888,
proxy: true,
proxies:
[
{
context: "/test",
rewrite: {
from: "^/test",
to: ""
}
}
]
}
}
Ekko emits events to allow implementations to handle when specific events occur. Descriptions of the events are listed below.
av:start
- Triggered when the Ekko server has been started.av:stop
- Triggered when the Ekko server has been stopped.av:request
- Triggered when a request has been received.av:response
- Triggered when a response file has been found for the requested route.av:fileNotFound
- Triggered when a response file could not be found -- either as a of an undefined route or the route's response file could not be found.av:redirect
- Triggered when a route specifies to redirect instead of responding with the contents of a file.
To add event handlers, register the events before starting the Ekko server.
var ekko = new Ekko(configPath);
ekko.on('av:request', function(req) {
/* your logic here */
});
ekko.start();
git clone https://github.com/Availity/availity-ekko
git checkout develop
git pull upstream develop
git checkout -b feature/branch-name
- Create some awesome code or fabulous bug fixes
- Open a pull request against the develop branch
- Wait for a commiter to merge and release
Robert McGuinness
Kasey Powers
Open source software components distributed or made available in the Availity Materials are licensed to Company under the terms of the applicable open source license agreements, which may be found in text files included in the Availity Materials.
Copyright (c) Availity, LLC