tiam v0.1.0
THE JSON SERVER MOCKUP TOOL
JSON server enables you to quickly provide a mockup server that serves RESTful protocols. You write the API in service.json and then provide corresponding responses for each API there. The responses can be read from .json files, .html files, .txt, or even provided as a string. You can write Javascript expressions in the .json or .html files as well to create a template that could provide dynamic responses.
Content
- Running the JSON server
- Configure the server using config.json
- Writing service.json
- API Definition
- JavaScript Expressions
- JSON template
- HTML template
- Support of S3 Hosted Files
- The Test Library API Reference
Running the JSON server
- Ensure you have
ts-nodeinstalled. issuenpm install -g ts-nodebefore advancing to the next step.
sudo npm install -g ts-node
npm install
npm startConfigure the server using config.json
To configure the JSON server, write or modify the config.json file.
{
"port": "port number for the server to serve",
"imports": {
"module identifier": "module name", ...
},
"serviceDescriptor": "./data/service.json"
}Port
The port number to which the server is served on.
Imports
An optional imports configuration allows you to load the node modules specified by module name. Once successfully imported at startup, you may refer to this module inside the .json or .html files using the module identifier. For example:
in config.json:
{
...
"modules": {
"moment": "moment",
"uu": "uuid",
"lo": "lodash"
}
}in orders.json:
{
"trackingId": "$ctx.trackingId = uu.v4()",
"created": "$moment()",
"expire": "$moment().add(30, 'days')",
"$exec": "$ctx.orderIndex.push(ctx.trackingId); ctx.orderIndex = lo.uniq(ctx.orderIndex)"
}Note: You'll need to issue
npm install <module>to install external modules before being able to import them to the service.
serviceDescriptor
You may specify the location of the service descriptor file using the serviceDescriptor configuration parameter. The content of this parameter can be
- An absolute path on local machine
- A relative path against the current working directory
- A URI describing S3 object (see S3 Support for more detail)
Writing service.json
You create service.json file to define APIs. The service.json file is loaded when the server starts. It is located at ./data/services.json by default. However, you can specify the different location in serviceDescriptor property on the config.json file. You may need to restart the server if you made changes to the service descriptor file.
To define an API, use the route path as a key. Under the route path key, defines the HTTP methods, i.e. GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD etc. A special method * can also be specified if you want the route path to serve for every HTTP methods.
{
"/api/orders": {
"GET": {
"response": "./data/orders.json"
},
"POST": {
"response": "./data/orders_result.json"
}
},
"/api/users": {
"GET": {
"response": "./data/users.json"
}
}
}The route path may contain parameters. Json server uses the path parameter syntax used in express.js, which uses a colon-leaded parameter names within the route path. The parameter can later be accessed in the scripts using ctx.request.params.<parameter>
{
"/api/users/:userId": "./data/user.json"
}in user.json:
{
"userId": "${ctx.request.params.userId}"
}You may use the variables in service definition file, such as in path.
{
"/api/users/:userId": {
"GET": {
"response": "./data/${ctx.request.params.userId}/user.json"
}
}
}API definition
Several ways to define a response for an API described in service.json file. You must define one of the following response types for an API in order to get it to function.
response- read from a fileerrorResponse- respond with HTTP status coderedirect- respond with 301 status code with redirect URLtextResponse- response with the given text
Note: The response types are mutual exclusive. They cannot be used together in a single API method.
response
Respond with the content of the specified file. The currently supported files are: .json, .html, and .txt.
{
"GET": {
"response": "./data/response.json"
}
}errorResponse
Respond with the given HTTP status code.
{
"GET": {
"errorResponse": "500"
}
}redirect
Direct the browser to the redirected url for this API.
{
"GET": {
"redirect": "http://www.google.com"
}
}textResponse
Respond with the given text
{
"GET": {
"textResponse": "Hello"
}
}You may use javascript expression in textResponse. See javascript expression for more details.
condition
Only use this particular definition if the condition is met, i.e. the expression returns true or javascript truthly value.
{
"GET": {
"condition": "ctx.request.params.userId === '2931'",
"response": "./data/user2931.json"
}
}headers
Define response headers
{
"GET": {
"headers": {
"Content-type": "text/html",
"Set-cookie": "session=29222"
}
}
}preScript
Provide Javascript to run before response is sent. The script is provided as a string.
Note: You do not need to use expression directive
${...}in thepreScriptvalue.
{
"/api/query": {
"*": {
"preScript": "ctx.data.queries = []",
"response": "./data/query-result.json"
}
}
}postScript
Provide Javascript to run after the response is sent. The script is provided as a string.
Note: You do not need to use expression directive
${...}in thepostScriptvalue.
{
"/api/product": {
"*": {
"response": "./data/product.json",
"postScript": "ctx.data.summary = Math.round(ctx.data.price)"
}
}
}Javascript Expression
To allow dynamic generation of content or configuration, you may use javascript expression in your json values. The expression can be defined inside ${...} directive and can be used in mixed with the string value.
The following is an example of how expressions can be used:
{
"values": "${a}, ${b}, ${c}",
"average": "${(a + b + c)/3}"
}Note: If the expression spans an entire string value, the type of result will be that of the result of the expression. For example, if your expression returns a number, the property value will be a number. If you need the expression that returns numeric (or other primitive types such as boolean, null, or undefined) to be represented as a string, use the
String(...)function. For example,"values": "${String(true)}"would be interpolated to"values": "true", while the"values":"${true}"results in"value": true.
JSON template
The JSON files you defined in the service.json file as the values to the response property are JSON templates. A JSON template can be a static content, having no expressions or directives, or dynamic, with expressions and/or directives within them. The dynamic generation of JSON file according to the template is a powerful feature of JSON server, which enables you to generate test cases that work for you.
Use of Variables in Javascript Expressions
The Context variable
The context variable can be accessed in the expression as a ctx variable. There are useful properties of this context variable that you can use. They are:
ctx.requestrepresents the current request. It is a Request instance fromexpressjsframework.ctx.datarepresents the globally accessible data where you can declare variables to use with the other APIs.
JSON Directives
In JSON templates, you can use JSON Server directive to control the fields. The JSON directive is described as a JSON object literal with the key (property name) beginning with a dollar sign ($) denoting the command.
$array directive
Used to create an array of repeating element based on the given template.
{
"data": {
"$array": {
"count": 10,
"element": "${ctx.i}"
}
}
}The element template can include dynamic expressions as same as that applies with the JSON templates. A special variable ctx.i is available in the context for the element template, which contains the current iteration number.
Properties
countThe number of generated elementselementThe element template.
$exec directive
Used to execute a Javascript statement without generating values in any outputs to the target field.
Note: You do not use string interpolation marker
${...}for a statement provided to$exec
For example, for this json template:
{
"field": { "$exec": "ctx.lastCall = new Date()" }
}Generates the output as:
{}$csv directive
Reads records in a CSV file to create an array of templated elements.
{
"$csv": {
"file": "file path",
"element": "string, object, or any types",
"firstLineHeader": false,
"headers": "optional string array of header variable names, defined in the same sequence againt columns",
"delimiter": "optional delimiter. Default to comma"
}
}parameters:
fileSpecifies path to the CSV file.elementDefines the element template. Can be a string (with expressions), object, or any types.firstLineHeaderSet to true if the first line on the CSV file defines header. If so, the headers will be used as a subscript tocolin the context variable. Default tofalse.headersArray of header names to override CSV file header, or when they are absent. The headers will be used as a subscript tocolin the context variable.delimiterA field delimiter for this CSV file.
$if directive
Conditionally return the element defined in then property if the condition implies JavaScript truthly value. Otherwise, the else element is returned, if defined. Otherwise, the target field is eliminated.
Note: You need to use Javascript expression
${...}forconditionif you plan to provide expression to evaluate rather than a constant string or a value.
{
"pricing": {
"$if": {
"condition": "${data.price > 200}",
"then": "expensive",
"else": "inexpensive"
}
},
"errorMessage": {
"$if": {
"condition": "${data.error}",
"then": "${data.errmsg}"
}
}
}Note: Unlike the full-fleged languages, JSON-server DSL does not defer the evaluation of
thenstatements to when the condition is true, as well as for anelsewhen the condition evalues to false. JSON server pre-evaluates the entire JSON structure before directive evaluation so all expressions are evaluated regardless of theconditionresulting value.
HTML template
The current version does not support dynamic HTML content generation.
Support of S3 Hosted Files
JSON Server supports AWS S3 hosted files in most of the configuration and descriptors that require file path. To refer to S3 stored content, simply use s3:// URI scheme in place of the path.
For example, in config.json you may use:
{
"serviceDescriptor": "s3://your-s3-bucket-name/path/to/object.json"
}The Test Library API Reference
Utilities that are commonly required for convenience in creating mock API are preloaded by default. This bundle of utilities can be accessed under lib namespace. They can be used in any expression evaluations on both service definition file and the template files.
lib.condition()
Use as an expression in place of if statement. Condition returns the then evaluation if the condition is true. Otherwise, it returns the result of else evaluation.
Note: The
ifand the conditional expression in Javascript can also be used. This interface is just provided for convenience.Declaration:
lib.condition(condition: boolean, then: () => any, else: () => any): any
example
{
"days": "${lib.condition(ctx.days > 30, () => days - 10, () => days + 20)}"
}lib.randomDigits()
Returns a random number or letters in the given character class as string for the given number of digits. Useful for generating random fix-length string IDs.
Declaration
lib.randomDigits(len: number = 8, charClass: string = lib.CC_NUMBERS): string
Parameters
lenoptional number of digits to be returnedcharClassoptional string of available characters to pick at random- The library has provided constant strings for mostly used character classes
lib.CC_ALPHANUMfor Alphanumeric (numbers and capital letters, 0-9 A-Z)lib.CC_MIX_ALPHANUMfor Alphanumeric with mixed character cases (0-9 A-Z a-z)lib.CC_NUMBERSfor numeric digits (0-9)lib.CC_CAPITALSfor capital letters (A-Z)lib.CC_LOWERCASESfor lowercase letters (a-z)- You can also use them in mix, for example
lib.CC_LOWERCASES + lib.CC_CAPITALS.
- The library has provided constant strings for mostly used character classes
Example
{
"username": "${lib.randomDigits(lib.randomNumber(15,3), lib.CC_CAPITALS)}",
"password": "${lib.randomDigits(16, lib.CC_MIX_ALPHANUM + '!@#$%^&*()_-+=\\/.\\'\"<>?{}[]')"
}lib.randomNumber
Returns the random number in the range of the given max, min inclusive.
Declaration
lib.randomNumber(max: number = 100, min: number = 0)
Parameters
maxoptional maximum possible number to return, inclusive. Default to 100minoptional minimum possible number to return, inclusive. Default to 0
Example
{
"price": "USD ${lib.randomNumber(100)}",
"height": "${lib.randomNumber(210, 140)} cm"
}7 years ago