If you have never defined RESTful services yet, then you might find useful the books and other readings listed in the References.
The services can be specified under the services
folder. Each service should have its own subdirectory. A service subdirectory must contain at least a service.yml
descriptor file, and any other files, mainly JSON or XML mock data and validation schemas.
The newly created project contains a sample service descriptor such as services/monitoring/isAlive/service.yml
.
Below you can see its (a bit shortened) content:
name: Monitoring that server is alive
description: |
It is a very simple service,
which makes possible to monitor that the server is running
and is able to answer HTTP requests
style: OPERATION
uriTemplate: /monitoring/isAlive
methods:
GET:
summary: Is server alive?
notes: Responses true if server is working
# implementation: monitoring.isAlive
request:
parameters: []
cookies: []
headers: []
responses:
-
name: OK
statusCode: &OkStatusCode 200
reason: &OkReason Successful execution
cookies: []
headers: []
mockBody: &OkMockBody getMonitoringIsAlive-responseBody.json
testCases:
-
name: Get Monitoring Is Alive
description: Successfully checks if server is alive
url: /monitoring/isAlive
template: testGetMethod.mustache
request:
parameters: []
cookies: []
headers: []
response:
name: OK
statusCode: *OkStatusCode
reason: *OkReason
cookies: []
headers: []
mockBody: *OkMockBody
The sample service descriptor defines a service, which is able to response to GET requests, and the response will be the content of the getMonitoringIsAlive-responseBody.json
file placed into the same directory where the service.yml
is there, as the mockBody
property determines.
The response also could be dynamically created by implementing it in JavaScript. The implementation
property of the request identifies the module and function of the code which defines the behavior of the service. At the moment it is commented out using the #
character, because only one of mockBody
or implementation
can exist.
You also can observe the usage of referencing feature provided by YAML. For example the value of the mockBody
property of the OK
response is labeled with &OkMockBody
and referenced by *OkMockBody
from the test-case. This allows you to define the mock file name that is getMonitoringIsAlive-responseBody.json
only once, and refer to it anywhere in the same file.
This sample descriptor file also can be used as a baseline to write your own definitions.
This section describes the structure of the service.yml
file, and the meaning of its properties.
In the whole service descriptor, you can use multi-line text in case of string-type fields. Moreover you can use Markdown format text in fields named such as: 'description', 'summary' and 'details'.
The top-level structure of a service descriptor is the following:
name:
(mandatory, string)
The name of the service.
For example: Monitoring that server is alive
description:
(mandatory, string)
Short description of the service.
For example: It is a very simple service, which makes possible to...
style:
(optional, string)
Tells whether it is an RPC-like OPERATION,
or a RESOURCE, which fully comply to the REST principles
Possible values: OPERATION | COLLECTION | RESOURCE
Default: OPERATION
urlPattern:
(deprecated)
Use the uriTemplate instead of it.
uriTemplate:
(mandatory, string)
The URL pattern of the service.
For example: /monitoring/isAlive
.
methods:
(mandatory, array)
The methods of the service specification.
There must be at least one method defined for the resource.
Currently only the most fundamental methods (GET, PUT, POST, DELETE) are provided.
The internal structure of every method is the following:
summary:
(mandatory, string)
Short summary of the service method.
notes:
(optional, string)
Details and notes about the method.
implementation:
(optional, string)
The implementation of the call in the following format:
<module>.<function>
. For details see the "Implement dynamic mocking behavior" section.
For example: monitoring.isalive
request:
(optional, object)
The detailed specification of request.
responses:
(mandatory, array)
The detailed specification of responses.
There can be several possible responses,
but at least one OK
response must be defined.
testCases:
(optional, array)
The detailed specification of test cases.
A method can contain zero or more test cases.
Default: an empty array
Every method must have a request property which describes the main attributes of the method to the given URL:
parameters:
(optional, array)
An array of request parameter descriptors.
Specification of the request parameters:
Default: an empty array
headers:
(optional, array)
Specification of the headers.
Default: an empty array
cookies:
(optional, array)
Specification of the cookies.
Default: an empty array
mockBody:
(optional, string)
The path to the file which contain the mock request body.
For example: postOperation-requestBody.json
.
Every method must have a responses array property which describes the main attributes of the possible responses to the request of the given URL. At least an OK
response must exist. Each response has the following structure:
Every method can have a testCases array property which describes the main attributes of the individual test cases to the request of the given URL. Each testCase has the following structure:
getMonitoringIsAlive-responseBody-validationSchema.json
.getMonitoringIsAlive-responseBody.json
.Similar to the validation of the config.yml
, when the server is started, or the generator is used, they check the validity of the service.yml
files too, so you might get error messages in case of wrong format or missing properties.
To see the detailed structure description of the service descriptor file, study the corresponding JSON validation schema files in the rest-tool-common
module:
These properties are all available during the documentation and test case generation process in the templates. It is also possible to place additional properties beside the mandatory ones, and they also can be used in templates, so you can customize your documentation or test cases using your own extensional data just like in case of the central config.yml
file.
The rest-tool
divides the services into two main classes:
OPERATION
style.COLLECTION
style. The URL pattern typically looks like this: /<collection-name>
, for example: /customers
.RESOURCE
style. The URL pattern typically looks like this: /<collection-name>/<resource-id>
, for example: /customers/0012301
.The following table summarizes the meaning of methods in case of the COLLECTION
style services:
Method | Description |
---|---|
POST | Create a new Resource of collection |
GET | Retrieves the whole collection |
PUT | Updates the whole collection |
DELETE | Delete the whole collection |
The following table summarizes the meaning of methods in case of the RESOURCE
style services:
Method | Description |
---|---|
POST | Create a new sub-resource of the resource |
GET | Retrieves one individual resource |
PUT | Updates one individual resource |
DELETE | Delete the identified resource |
The rest-tool
provides built-in command and templates for creating new services from any of the the tree styles mentioned above.
You can create a new service either manually creating and editing service.yml
files, or using the rest-tool
with the add
and/or add-bulk
command.
To add one service, you can use the rest-tool add
command:
$ rest-tool add -h
Usage: add [options]
Options:
-h, --help Output usage information
-t, --type [type] Defines the type
(OPERATION|COLLECTION|RESOURCE)
of the service (default: RESOURCE)
-p, --path <path> The path of the service description
relative to project-root/service/
-u, --uriTemplate <uriTemplate> The unique URL pattern of the service
-n, --name <name> The name of the
operation/collection/resource
-d, --desc <desc> The description of the service
-c, --config [configFileName] The name of the configuration file
(default: config.yml)
-v, --verbose Verbose mode
For example, to create a collection manager service, execute the following command:
$ rest-tool add -t COLLECTION \
-p /customers \
-u /customers \
-n Customers \
-d "A service to manage the collection of customers"
After the successful execution, you will find a new service under the
project-root/services/customers
folder. You can add/edit the files under this directory according to your needs.
The service descriptors you created will be added to the project-root/config.yml
and activated automatically.
It is also possible to create more than one service in one step with the rest-tool add-bulk
command:
$ rest-tool add-bulk -h
Usage: add-bulk [options]
Options:
-h, --help output usage information
-s, --services [services] The filename of which contains
the list of services to create
(for example: services.json)
-c, --config [configFileName] The name of the configuration file
(default: config.yml)
-v, --verbose Verbose mode
The following code fragment demonstrates a possible service list that can be used by the add-bulk
bulk command.
[
{
"type": "COLLECTION",
"path": "/orders",
"uriTemplate": "/orders",
"name": "Orders",
"description": "Order collection management",
"methods": [
"POST"
]
},
{
"type": "RESOURCE",
"path": "/orders/order",
"uriTemplate": "/orders/order",
"name": "Order",
"description": "Order management",
"methods": [
"POST"
]
},
{
"type": "OPERATION",
"path": "/filterOrders",
"uriTemplate": "/filterOrders",
"name": "Complex order filtering",
"description": "Complex filtering of orders collection",
"methods": [
"POST"
]
}
]
If the JSON content listed above is stored into a file named services.json
, it can be used with the following command:
$ rest-tool add-bulk -s services.json
Similar to the normal add
command, the newly created services will be added to the project-root/config.yml
file.
The service descriptors you create will be activated automatically, and they are listed under the services
property of the config.yml
file:
services:
- /monitoring/isAlive
# To add new services, put here the path of the directory
# that contains the service.yml
In case you want to disable a given service, you only have to comment that line out, or simply you can just remove it.
Just simply put any files beside the service.yml
and refer to them using the mockBody
fields in the service descriptor.
TBD.
The service descriptor either contains mockBody
properties under the response and test case objects that refer to mock data files, or it contains an implementation
property of the request
object. In this latter case you can call a server module, with your own implementation.
For more details see the Implement dynamic mocking behavior section.
If none of these properties are defined, the service is responding a JSON object, that is the service descriptor itself by default, in order to show the server is listening to the given URL.