- An Example Repo
- Getting Started
- Overview of Mock Files
- Overview of Initizalation Script
- Building the mock server using slurp mode
- Adding Paths to Mocks
- Adding Regex and String Pattern Paths to your Mocks
- How, Query, Param and Body work in mock files
- Subset and Structural Matching with JSON Schema
- Gotchas And FAQ
-
Create a script to start your mock server at the git root of your project
vim server.js
// Inside server.js const { init } = require('genuine-mock-server'); const mocks = [ { request: { method: 'get', path: '/api/helloworld/example', }, response: { data: { 'key': 'Hello World!', } }, }, ]; init({ port: 8080, mocks: mocks, }
-
Use your prefered script watcher (We recommend nodemon)
nodemon server.js
or
node server.js
-
Curl that bad-boy!
curl 'http://localhost:8080/api/helloworld/example'
There is also a second way to build the mock server, and that is using 'slurp' mode. You specify the path to the folders containing mock files, and a file-ending to slurp up into the mock server. Slurp mode is useful if you want a file-to-endpoint naming convention for storing your mocks.
-
Create a simple mock files directory
mkdir mocks
-
Create a simple mock file inside
mocks/
vim mocks/example.js
Note: folder structure, file names, etc DO NOT MATTER. Files are slurped recursively. A file named Foobar could map to any endpoint. Naming conventions are entirely up to you!
module.exports = [ { request: { method: 'get', path: '/api/helloworld/example', }, response: { data: { 'key': 'Hello World!', } }, }, ];
-
Create a script to start your mock server
vim server.js
const { init } = require('genuine-mock-server'); init({ port: 8080, pathToFiles: './mocks', filePattern: '*.js', // whatever file extension you want to target });
-
Use your prefered script watcher (We recommend nodemon)
nodemon server.js
or
node server.js
-
Curl that bad-boy!
curl http://localhost:8080/api/helloworld/example
module.exports = [
{
request: {
// ...
},
response: {
// ...
},
},
]
Key | Type | Description | Required |
---|---|---|---|
path | String | The api endpoint path (not including querystring) | required |
method | String | The http method | optional (defaults to GET) |
params | Object | An object of key / value pairs for path params | optional (defaults to {}) |
body | Object | An object of key / value pairs for the body request | optional (defaults to {}) |
query | Object | An object of key / value pairs for the querystring | optional (defaults to {}) |
matchType | String | A string to select the match algorithm (see JSON Schema) | optional (defaults to 'exact') |
Key | Type | Description | Required |
---|---|---|---|
waitTime | Integer | The time in milliseconds the mockserver will wait before responding | optional (defaults to 0) |
statusCode | Integer | The http status code in the response | optional (defaults to 200) |
data | Object | The data that will be returned in the response from the mock server | optional (by why would you leave it blank?) |
const { init } = require('genuine-mock-server');
init({
port: 8080,
pathToFiles: './mockServer/Mocks',
filePattern: '*.js', // whatever file extension you want to target
mocks: [
{
// ... stuff here
}
]
});
Key | Type | Description | Required |
---|---|---|---|
port | Integer | The port number for the mock server | required |
pathToFiles | String | The path to the top-level folder containing mock files | required (only if 'mocks' is not included) |
filePattern | String | The file pattern / file extension to be slurped up by the mock server | optional |
mocks | Array | An array of supplied mock objects. Useful if you want to supply programatically created mocks | required (only if 'pathToFiles' is not included) |
You can use both mock files defined inside a mock folder, or programatically added mock files, or both!
// only slurp mocks are added, since the other keys have been ommitted
const { init } = require('genuine-mock-server');
init({
port: 8080,
pathToFiles: './mocks',
filePattern: '*.js'
});
// only provided mocks are added, since the other keys have been ommited
const { init } = require('genuine-mock-server');
const mocks = [
{
request: {
method: 'get',
path: '/api/helloworld/simple',
},
response: {
data: {
'key': 'Hello World!',
}
},
},
];
init({
port: 8080,
mocks: mocks,
});
// Here, both provided mocks, AND slurped mocks are used
const { init } = require('genuine-mock-server');
const mocks = [
{
request: {
method: 'get',
path: '/api/helloworld/simple',
},
response: {
data: {
'key': 'Hello World!',
}
},
},
];
init({
port: 8080,
mocks: mocks,
pathToFiles: './mockServer/Mocks',
filePattern: '*.js', // whatever file extension you want to target
});
Note: Whichever method you choose is up to you. Provided mocks are added first, then slurped mocks.
If you want, you can simply write out different paths by hand in each mock blob. The ability to specify different paths on a per-mock basis is useful if you're building out mocks programatically, and want complete control.
module.exports = [
{
request: {
method: 'get',
path: '/api/helloworld/firstpath',
},
response: {
data: {
'key': 'Hello World!',
}
},
}
{
request: {
method: 'get',
path: '/api/helloworld/secondpath',
},
response: {
data: {
'key': 'Hello World!',
}
},
}
];
Writing out the same path over and over again is error prone, so a helper method is included to make things easier, should you so desire.
const { defaultPath } = require('genuine-mock-server');
module.exports = defaultPath('/api/helloworld/defaultpath/', [
{
request: {
// default path gets added automagically
method: 'get',
},
response: {
data: {
'key': 'I use the default path',
}
},
},
{
request: {
// default path gets added automagically
method: 'delete',
},
response: {
data: {
'key': 'I use the default path as well!',
}
},
},
]);
Note: This method is mostly just a simple reduce function, but it won't clobber any paths you HAVE defined. See below for an example
You can, if you so desire, add the same path to all mock files, except for a few of them.
const { defaultPath } = require('genuine-mock-server');
module.exports = defaultPath('/api/helloworld/defaultpath/', [
{
request: {
// default path gets added automagically
method: 'get',
},
response: {
data: {
'key': 'I use the default path',
}
},
},
{
request: {
// default path gets added automagically
method: 'delete',
},
response: {
data: {
'key': 'I use the default path as well!',
}
},
},
{
request: {
path: '/api/helloworld/notdefaultpath' // Since the path is defined, it is NOT overriden
method: 'delete',
},
response: {
data: {
'key': 'My path was defined, so I wont be overriden',
}
},
},
]);
Under the hood, genuine-mock-server
uses express
, so regex paths are standardized
and simple.
// Adding a regex as your path:
module.exports = [
{
request: {
path: new RegExp(/api/g),
.../
},
response: {
// ...
},
},
]
// gets translated under the hood to
app.get(yourRegexHere, () => {
// your mock data gets returned
})
string-patterns
like '/ab(cd)?e'
are also supported (as they are part of the express)
routing. Consult the express
docs for more information: link
Note: Same as any other routing framework, be mindfull of how your regex paths are intercepting.
Like express
, catchall routes will intercept instead of other already-defined paths.
This may, or may not, be what you intended. If in doubt, register your regex paths later,
after the other mocks.
module.exports = [
{
request: {
query: {
// ...
},
body: {
// ...
},
params: {
// ...
}
},
response: {
// ...
},
},
]
Genuine Mock server follows a simple strategy for mocking files. Request
represents
any given http request sent to the server, with a given set of paramaters. Any request
that exactly matches these paramaters will return the data supplied in response
.
For more information on how exact matching works, view: How exact matches work
Lets say you wanted to mock any GET request to /api/helloworld/people?name=jimmy
.
module.exports = [
{
request: {
path: '/api/helloworld/people'
query: {
name: 'jimmy', // A GET request to '/api/helloworld/people?name=jimmy', would match this request
},
},
response: {
data: {
someKey: "I am the get querystring example response!"
}
},
},
]
// Example semi-psuedocode axios
axios.get('/api/helloworld/people?name=jimmy');
// Example response
{
someKey: "I am the get querystring example response!"
}
Lets say you wanted to mock any POST request to /api/helloworld/person/:name
,
where the :name
is equal to 'jimmy'
module.exports = [
{
request: {
path: '/api/helloworld/person/:name'
path: {
name: 'jimmy', // A request to '/api/person/jimmy' would match this request!
},
},
response: {
data: {
someKey: "I am the path param example response!"
}
},
},
]
// Example semi-psuedocode axios
axios.post('/api/helloworld/person/jimmy');
// Example response
{
someKey: "I am the path param example response!"
}
Lets say you wanted to mock a POST request to /api/helloworld/people
,
with a json body of { name: 'jimmy' }
module.exports = [
{
request: {
path: '/api/helloworld/person'
body: {
name: 'jimmy', // A POST request to the above path with the given body would match this request!
},
},
response: {
data: {
someKey: "I am the Body example response!"
}
},
},
]
// Example semi-psuedocode axios
axios.post('/api/helloworld/person', {
name: 'jimmy',
});
// Example response
{
someKey: "I am the body example response!"
}
Lets say you wanted to mock any POST request to /api/helloworld/people/:name/filter?age=28
,
with a path param of { name: 'jimmy' }
, and a json body of { occupation: 'teacher' }
module.exports = [
{
request: {
path: '/api/helloworld/people/:name/filter',
query: {
age: '28',
},
params: {
name: 'jimmy'
},
body: {
occupation: 'teacher',
},
},
response: {
data: {
someKey: "I am the mixed request example data"
}
},
},
]
// Example semi-psuedocode axios
axios.post('/api/helloworld/people/jimmy/filter?age=28', {
occupation: 'teacher',
});
// Example response
{
someKey: "I am the mixed request example data"
}
For more information on what the mock files look like with a mix of path params, querystrings, and request bodies, be sure to check out the example repo (Sometimes an example is worth a thousand words!)
genuine-mock-server
also alows for mapping mocks-to-requests using Json Schema
JSON Schema Standard
JSON Schema Node Package
This means you can match requests based on generalized subset descriptions of the incoming data, instead of EXACT matches as used by default
module.exports = [
{
request: {
path: '/api/helloworld/schema',
query: {
age: '28',
},
},
response: {
data: {
someKey: "I am the example data"
}
},
},
]
// 1. Example semi-psuedocode axios
axios.get('/api/helloworld/schema?somekey=valuehere');
// 2. Mock server compares predescribed schema, to incoming request using JSON schema
{
required: ['query'],
properties: {
query: {
properties: {
somekey: {
type: 'string',
const: 'valuehere'
}
}
}
}
}
// compared against ALL recieved request data
{
query: {
somekey: 'valuehere'
},
body: {},
params: {},
}
// 3. Example response if it matches
{
someKey: "I am the example data"
}
// 4. Otherwise, mock server keeps itterating
When you create a mock file involving query / querystrings, be aware that values should ALWAYS be strings. This is due in part to the HTTP spec, which uses strings under-the-hood, and express itself, which parses querystring values into key value pairs (with values being strings)
Further reading on the subject and implementation from Node / Express
// inside your mock file
//GOOD!
module.exports = [
{
request: {
path: '/api/helloworld/filter',
query: {
age: '28', // Good, your mock value is a string
},
},
response: {
// ...
}
]
//BAD!
module.exports = [
{
request: {
path: '/api/helloworld/filter',
query: {
age: 28, // BAD!!! This will not match, the server will recieve 28 as a string
},
},
response: {
// ...
}
]
If you're using the default mock matching (i.e exact matching);
{
request: {
// ...
matchType: 'exact' // Genuine-mock-server assumes this matchtype by default
},
response: {
// ...
}
}
you need to be sure you're meeting all the data requirements, no more, no less.
- If you're supply a subset of the data, your mock will not be matched
- If you supply a superset of the data, your mock will not be matched
// Example of a potential problem below
const mocks = [
{
request: {
method: 'get',
path: '/api/helloworld/mismatch',
},
response: {
data: {
'key': 'If you include MORE data, I wont be matched',
}
},
},
];
// 1. Example semi-psuedocode axios
axios.get('/api/helloworld/mismatch?extra=data');
// 2. The mock server recieves a `get` request for '/api/helloworld/mismatch',
// with query data...
query: {
extra: 'data'
}
// Your mocked WILL NOT be matched, since your mock declares `query` have no data
{
request: {
method: 'get',
path: '/api/helloworld/mismatch',
// <------------ No query data provided, considered empty!
},
response: {
data: {
'key': 'If you include MORE data, I won't be matched,
}
},
},
// 3. No mock is found, as expected
If you need more nuanced generic-matching, consider using: matchType: 'schema'