From 5a5403282411d5c871748fb715ebd91b0cd1b3d5 Mon Sep 17 00:00:00 2001 From: Quentin Fayet Date: Wed, 22 Aug 2018 14:40:21 +0200 Subject: [PATCH 1/7] Add HTTP mocking documention first draft --- docs/http_mocking.rst | 969 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 969 insertions(+) create mode 100644 docs/http_mocking.rst diff --git a/docs/http_mocking.rst b/docs/http_mocking.rst new file mode 100644 index 0000000..29f2bfc --- /dev/null +++ b/docs/http_mocking.rst @@ -0,0 +1,969 @@ +============ +HTTP Mocking +============ + +Mockservr allows you to mock HTTP endpoints, defined through YAML files. Usin HTTP Mocking, you can easily and +rapidely mock any HTTP based API. + +******** +Overview +******** + +As for any mock in Mockservr, it must be defined in a YAML file, with the `.mock.yaml` or `mock.yml` file extension. + +HTTP endpoints are defined under a single object, named `http`, which can either contain an array of endpoints +or a single object describing a single endpoint. + +Accessing the HTTP endpoints +============================ + +Once Mockservr is up and running as described in :ref:`quickstart`, it is possible to access the endpoints through +your localhost and the port `8085`. + +.. note:: + The port on which Mockservr can be reached through HTTP can be customized, either by using the `-p` option if running + with Docker (see :ref:`quickstart_running_with_docker`) or by using the `services.XX.port` option if running under + docker-compose (see :ref:`quickstart_running_with_docker_compose`). + +Defining the HTTP endpoints +=========================== + +There are two ways to define the HTTP endpoints in the mock configuration file. + +- If your mock aims to contain a single endpoint, the endpoint is described as un object under `http`. +- If your mock aims to contain many endpoints, the endpoints are described in an array under `htttp`. + +Example of single-endpoint mock +------------------------------- + +Using an object under `http` will define a single-endpoint mock: + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + } + } + +The endpoint is then accessible through HTTP: + +.. code-block:: sh + + curl -XGET 'http://localhost:8085/foo' + +.. note:: + The endpoint defined above is accessible using any HTTP verb. More about defining which HTTP verb to be used in + :ref:`http_mocking_method_option`. + +Example of multiple endpoints mock +---------------------------------- + +Using an array of objects under `http` will define multiple endpoints for the mock: + +.. code-block:: yaml + :caption: YAML + + http: + - + request: + path: '/foo' + response: + body: 'Hello World!' + - + request: + path: '/bar' + response: + body: 'Hello bar!' + +.. code-block:: json + :caption: JSON + + { + "http": [ + { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + }, + { + "request": { + "path": "/bar" + }, + "response": { + "body": "Hello bar!" + } + } + ] + } + +These endpoints are then accessible through HTTP: + +.. code-block:: sh + + curl -XGET 'http://localhost:8085/foo' + curl -XGET 'http://localhost:8085/bar' + +******* +Request +******* + +This section covers the `http.request` part of the endpoint definition ; it defines how Mockservr will match the +incoming HTTP requests, and what response it will serve to the client. + +Request Definition +================== + +The `http.request` may either be a string, an object or an array. + +Basic definition of a Request +----------------------------- + +The simpliest way to define a Request is by only defining its path. Mockservr allows you to write this path directly +under `http.request`, using a string, such as: + +.. code-block:: yaml + :caption: YAML + + http: + request: '/foo' + response: + body: 'Hello World!" + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": "/foo", + "response": { + "body": "Hello World!" + } + } + } + +The endpoint is then accessible through HTTP: + +.. code-block:: sh + + curl -XGET 'http://localhost:8085/foo' + +.. note:: + This way to define an endpoint is equal to: + + .. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello World!' + + .. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + } + } + +.. note:: + If you intend to use more specific definition of the incoming requests, see +:ref:`http_mocking_defining_single_request`. + +.. _http_mocking_defining_single_request: + +Defining a single Request +------------------------- + +If your endpoint must react to single type of Request, then you can use an object to define it. To learn about all +possible options to define the Request, please see :ref:`http_mocking_request_options`. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + } + } + +The endpoint is then accessible through HTTP: + +.. code-block:: sh + + curl -XGET 'http://localhost:8085/foo' + +Defining multiple Request +------------------------- + +In case your endpoint should serve a similar Response to requests that may have different shapes, you can define multiple +matching Requests for the endpoint, by using an array. + +.. code-block:: yaml + :caption: YAML + + http: + request: + - + path: '/foo' + - + path: '/bar' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": [ + { + "path": "/foo" + }, + { + "path": "/bar" + } + ], + "response": { + "body": "Hello World!" + } + } + } + +The endpoint is then available through different HTTP requests: + +.. code-block:: sh + + curl -XGET 'http://localhost:8085/foo' + curl -XGET 'http://localhost:8085/bar' + +.. _validator: + +Request Validators +================== + +For an incoming HTTP to match a defined Request, it must be positively matched against all the options defined for the +endpoint in the mock file. + +To perform this, you may use a Validator ; it is an object with two properties: + +- `type` which defines the type of Validator to use +- `value` which is the expected value used by the Validator. + +Mockservr comes with a **Validator inference** feature, which means, if you do not explicitly define which Validator +to use, Mockservr will guess it for you. + +`scalar` Validator +------------------ + +The `scalar` Validator performs an exact match between the expected value and the given one. This Validator +is automatically inferred when the value is a string, a number or a boolean value. + +Some syntactic sugar are also available, to alias the `scalar` Validator and make the definition of the endpoints +more clear. As such, the types `string`, `number` and `boolean` are all alias to the `scalar` Validator. + +Example +^^^^^^^ + +For example, you can use the `scalar` Validator to validate the path. All the following definitions are equals: + +Using the `scalar` Validator +"""""""""""""""""""""""""""" + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: + type: 'scalar' + value: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": { + "type": "scalar", + "value": "/foo" + } + }, + "response": { + "body": "Hello World!" + } + } + } + +Using the `string` Validator +"""""""""""""""""""""""""""" + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: + type: 'string' + value: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": { + "type": "string", + "value": "/foo" + } + }, + "response": { + "body": "Hello World!" + } + } + } + +Using the Validator inference +""""""""""""""""""""""""""""" + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + } + } + +`range` Validator +----------------- + +The `range` Validator may be used to define a range in which the given value should lie. The `value` is an object +composed of two entries: + +- `min`: The lower bound of the range (inclusive) +- `max`: The upper bound of the range (inclusive) + +Both ranges must be numbers (either integer or floats). An example of the `range` Validator can be is presented in +:ref:`http_mocking_query_option`. + +`regex` Validator +----------------- + +The `regex` Validator may be used to match a given value against a regular expression. As such, the `value` entry +is the given regular expression. References about Javascript Regular Expressions can be found on Mozilla_. + +.. _Mozilla: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + +An example of the `regex` Validator can be is presented in :ref:`http_mocking_method_option`. + +.. _http_mocking_request_options: + +`anyOf` Validator +----------------- + +The `anyOf` Validator may be used to match one of several given values. Under the hood, Mockservr is performing +Validator inference ; it allows to use scalar values (string, number, ...) in the array. However, it is possible +to use Validators inside the array, giving you the possibility to use regular expression, for example. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: + type: 'anyOf' + value: + - '/foo' + - '/bar' + - + type: 'regex' + value: '/^\/p.*$/' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": { + "type": "anyOf", + "value": [ + "/foo", + "/bar", + { + "type": "regex", + "value": "/^\/p.*$/" + } + ] + } + }, + "response": { + "body": "Hello World!" + } + } + } + +The endpoint is then available through different HTTP requests: + +.. code-block:: sh + + curl -XGET 'http://localhost:8085/foo' + curl -XGET 'http://localhost:8085/bar' + curl -XGET 'http://localhost:8085/plop' + +`object` Validator +------------------ + +The `object` Validator in itself does not perform any validation. Instead, the value is an object, in which one +or more validators are defined. + +`typeOf` Validator +------------------ + +The `typeOf` Validator validates that the given value corresponds to the expected type. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: + type: 'typeof' + value: 'string' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": { + "type": "typeof", + "value": "string" + } + }, + "response": { + "body": "Hello World!" + } + } + } + +The example above will match any incoming request, as path is always a string. + +.. note:: + As Mockservr is using Javascript, running the `typeOf` validator against `null` won't be working as expected. + +Request Options +=============== + +This section describes all the options available for a Request. For an incoming HTTP request to match a defined +Request, it must match positively against all options. + +The options are defined under the `request` object of an HTTP endpoint. + +Each option can be described as a :ref:`validator`, but may also be described as a scalar value, for which Mockservr +will perform validator inference. + +Defining multiple sets of options for a single Request +------------------------------------------------------ + +It is possible to describe multiple sets of options to describe a Request. To do so, the `request` must be an array of +objects instead of a single object. + +For each incoming HTTP request, Mockservr will try to match against all different Requests that have been defined. + +It allows you to describe several ways to reach a single endpoint. + +.. code-block:: yaml + :caption: YAML + + http: + request: + - + path: '/foo' + - + path: '/bar' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": [ + { + "path": "/foo" + }, + { + "path": "/bar" + } + ] + "response": { + "body": "Hello World!" + } + } + } + +Then, the two following HTTP requests will lead to the same response: + +.. code-block:: sh + + curl -XGET 'http://localhost:8085/foo' + curl -XGET 'http://localhost:8085/bar' + +`basepath` option +----------------- + +The `basepath` option allows to define the base path of the request. It is mainly useful to group requests by their +base path in the Mockservr GUI. + +.. code-block:: yaml + :caption: YAML + + http: + request: + basepath: '/foo' + path: '/1' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "basepath": "/foo", + "path": "/1" + }, + "response": { + "body": "Hello World!" + } + } + } + +`body` option +------------- + +The `body` option allows you to define what the incoming HTTP request's body must look like. For it to be working, the +`Content-Type` header must be defined as `application/x-www-form-urlencoded` or as `application/json`. + +All types of validator may be used with the `body` option. + +In case the body is a JSON or a form, it is possible to use an object under `body`. In this case, the keys of the object +will be used to find the corresponding key in the HTTP request's body, and it will be matched against the value specified +at the corresponding key. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + body: + name: 'John' + last_name: ['Doe', 'Bar'] + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "body": { + "name": "John", + "last_name": ["Doe", "Bar"] + } + }, + "response": { + "body": "Hello World!" + } + } + } + +In the above example, the JSON or form body must define two key/value pairs: The first one is `name` and its value +must be "John" (the `string` validator is automatically inferred) ; the second one is `last_name` and its value must +either be "Doe" or "Bar" (the `anyOf` validator is automatically inferred). + +The incoming request's body may also be a simple string or any other scalar. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + body: "Hello" + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "body": "Hello" + }, + "response": { + "body": "Hello World!" + } + } + } + +`headers` option +---------------- + +The `headers` options allows the control of the incoming HTTP request. This option can only be an object with +key/value pairs. The key is the header's name, and the value is the expected value. + +The value can be any type of validator, allowing a fine-grain control of the headers. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + headers: + Content-Type: ['application/json', 'application/x-www-form-urlencoded'] + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "headers": ['application/json', 'application/x-www-form-urlencoded'] + }, + "response": { + "body": "Hello World!" + } + } + } + +In the above example, the endpoint will be triggered in the incoming HTTP request contains a `Content-Type` header +and if its value is either `application/json` or `application/x-www-form-urlencoded`. + +`maxCalls` option +---------------- + +The `maxCalls` option defines a maximum calls count for a given Request. This gives the possibility to simulate API +rate limits, for example. + +The `maxCalls` option does not provide validator inference, as the only possible value is a plain integer. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + maxCalls: 5 + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "headers": 5 + }, + "response": { + "body": "Hello World!" + } + } + } + +In the above example, the Request is going to be positively matched 5 times. When the 6th call arrives, Mockservr will +not match it positively against this Request. + +.. _http_mocking_method_option: + +`method` option +--------------- + +The `method` option defines which type of HTTP requests will match positively with the endpoint. Apart of the usual +HTTP verbs (GET, POST, ...), it is possible to set custom HTTP verbs. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + method: ['GET', 'POST'] + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "method": ["GET", "POST"] + }, + "response": { + "body": "Hello World!" + } + } + } + +The Request defined above will match positively against any incoming HTTP request which is a GET or a POST request. d + +`path` option +------------- + +The `path` option defines on which path the endpoint can be reached. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + }, + "response": { + "body": "Hello World!" + } + } + } + +The example above is an endpoint reachable on the `/foo` path of Mockservr (typically `http://localhost:8085`) + +.. _http_mocking_query_option: + +`query` option +-------------- + +The `query` option defines how the incoming HTTP request's query parameters will be matched. **It must be an object** +in which each key/value pair correspond to a query parameter/value. The value in each key/value pair is a :ref:`validator`. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + query: + action: 'show' + id: 1 + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "query": { + "action": "show", + "id": 1 + } + }, + "response": { + "body": "Hello World!" + } + } + } + +To match the above Request, the incoming HTTP request must be of the form `/foo?action=show&id=1` + +******** +Response +******** + +When Mockservr matches an incoming HTTP request to a Request defined in an endpoint, it will send back a HTTP response. +The definition of this response lies into the `http.response` object. + +It is possible to define several Responses for an endpoint and the way Mockservr should pick the right Response from +the incoming HTTP request. + +Response Definition +=================== + +A Response is defined by a set of options that describe Mockservr how to build the HTTP response to an incoming HTTP +request that has been match successfully to the endpoint. + +It is also possible to define several possible Responses for a single endpoint. To do so, `http.response` must be an +array of objects, each object defining a possible Response. In that case, each object must also contains some options +that will tell Mockservr how to pick the right Response ; otherwise, Mockservr will pick the first Response in the +array. + +Defining a single Response +-------------------------- + +Basically, an HTTP response is composed of a body and a status code. By default, the status code returned by Mockservr +is 200 if not defined otherwise. + +A basic Response definition would be: + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + } + } + +This endpoint definition will match any incoming request on `/foo`, and the HTTP response's body will be "Hello World!" +with HTTP status code 200. + +Defining several possible Responses +----------------------------------- + +Using an array instead of an object under `http.response`, it is possible to define several possible Response for a +single endpoint. It is then possible to give a weight to each of the Responses, and Mockservr will pick one of the +Response randomly, according to their respective weight. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + - + body: 'Hello World!' + weight: 0.5 + - + body: "Bye World!" + weight: 0.5 + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": [ + { + "body": "Hello World!", + "weight": 0.5 + }, + { + "body": "Bye World!", + weight: 0.5 + } + ] + } + } + +For the endpoint defined above, Mockservr will pick a random Response ; as both their weights are 0.5, they'll be pick +randomly with equal chances. See :ref:`http_mocking_response_weight_option` + +Response Options +================ + +.. _http_mocking_response_weight_option: + +`weight` option +--------------- + From ca27431dc2474395c6e3c782842020735e00b71a Mon Sep 17 00:00:00 2001 From: Quentin Fayet Date: Wed, 22 Aug 2018 14:40:38 +0200 Subject: [PATCH 2/7] Add quickstart documentation first draft --- docs/quickstart.rst | 55 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/quickstart.rst diff --git a/docs/quickstart.rst b/docs/quickstart.rst new file mode 100644 index 0000000..e9eedde --- /dev/null +++ b/docs/quickstart.rst @@ -0,0 +1,55 @@ +.. _quickstart: + +========== +Quickstart +========== + +Mockservr is designed to be as user-friendly as possible, hence it can be integrated into an existing stack really +quickly, immediately providing a way to mock APIs. + +******************* +System requirements +******************* + +In order to run mockservr in the easiest way, we provide docker images. + +The minimum requirements on the host system are: + +- Docker >= 18 (https://www.docker.com/) + +.. _quickstart_running_with_docker: + +******************* +Running with docker +******************* + +One way of running Mockservr is through Docker. + +.. code-block:: sh + + docker run -dit --name my-mockservr -p 8085:80 -p 4580:4580 -v "$PWD":/usr/src/app/mocks mockservr/mockservr:latest + +From now, all defined mocks will be accessible through `http://localhost:8085`. + +.. _quickstart_running_with_docker_compose: + +*************************** +Running with docker-compose +*************************** + +Assuming your stack runs using docker-compose, Mockservr can be easily integrated in your docker-compose.yaml file : + +.. code-block:: yaml + + services: + # ... + + mockservr: + image: mockservr/mockservr:latest + volumes: + - ./mocks:/usr/src/app/mocks + ports: + - 8085:80 + - 4580:4580 + +From now on, all defined mocks will be accessible through `http://localhost:8085`. From 3ffb0940f5fdc0c51f6679d603786f2b4a9388fc Mon Sep 17 00:00:00 2001 From: Quentin Fayet Date: Wed, 22 Aug 2018 14:41:31 +0200 Subject: [PATCH 3/7] Add documentation index --- docs/index.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs/index.rst diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..6b028e1 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,21 @@ +Mockservr Documentation +======================= + +Mockservr is an API mocking system, allowing to configure endpoints, specifying requests details and +responses. + +- YAML or JSON endpoint configuration +- Ability to use Apache Velocity Template files to dynamically adapt responses to requests parameters +- Available under docker image, see dockerhub to be easily integrated into a development / test stack + +Using Mockservr gives the ability to avoid real API calls to external providers, while ensuring that the code +carries no logic related to the environment. + +Summary +======= + +.. toctree:: + :maxdepth: 3 + + quickstart + http_mocking From a9e3d18d4f22022484d9ab8997ae2318dd696e6c Mon Sep 17 00:00:00 2001 From: Nicolas Couet Date: Thu, 23 Aug 2018 17:55:54 +0200 Subject: [PATCH 4/7] Update documentation option --- docs/API.rst | 5 + docs/http_mocking.rst | 359 +++++++++++++++++++++--------------------- docs/index.rst | 2 + docs/quickstart.rst | 12 +- 4 files changed, 193 insertions(+), 185 deletions(-) create mode 100644 docs/API.rst diff --git a/docs/API.rst b/docs/API.rst new file mode 100644 index 0000000..88b1428 --- /dev/null +++ b/docs/API.rst @@ -0,0 +1,5 @@ +.. _API: + +=== +API +=== diff --git a/docs/http_mocking.rst b/docs/http_mocking.rst index 29f2bfc..77fb0ad 100644 --- a/docs/http_mocking.rst +++ b/docs/http_mocking.rst @@ -2,23 +2,22 @@ HTTP Mocking ============ -Mockservr allows you to mock HTTP endpoints, defined through YAML files. Usin HTTP Mocking, you can easily and +Mockservr allows you to mock HTTP endpoints, defined through YAML/JSON files. Usin HTTP Mocking, you can easily and rapidely mock any HTTP based API. ******** Overview ******** -As for any mock in Mockservr, it must be defined in a YAML file, with the `.mock.yaml` or `mock.yml` file extension. +As for any mock in Mockservr, it must be defined in a YAML/JSON file, with the `.mock.yaml` or `mock.yml` or `mock.json` file extension. -HTTP endpoints are defined under a single object, named `http`, which can either contain an array of endpoints -or a single object describing a single endpoint. +HTTP endpoints are defined under a single object, named `http`, which should contain an array of endpoints. Accessing the HTTP endpoints ============================ Once Mockservr is up and running as described in :ref:`quickstart`, it is possible to access the endpoints through -your localhost and the port `8085`. +your localhost and the port `8080`. .. note:: The port on which Mockservr can be reached through HTTP can be customized, either by using the `-p` option if running @@ -28,53 +27,15 @@ your localhost and the port `8085`. Defining the HTTP endpoints =========================== -There are two ways to define the HTTP endpoints in the mock configuration file. +There are two ways to define the HTTP endpoints in the Mockservr. -- If your mock aims to contain a single endpoint, the endpoint is described as un object under `http`. -- If your mock aims to contain many endpoints, the endpoints are described in an array under `htttp`. +- Describe endpoints in an array under `http` in a YAML/JSON file +- Use :ref:`API` -Example of single-endpoint mock -------------------------------- +Example of endpoints mock file +------------------------------ -Using an object under `http` will define a single-endpoint mock: - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: '/foo' - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": "/foo" - }, - "response": { - "body": "Hello World!" - } - } - } - -The endpoint is then accessible through HTTP: - -.. code-block:: sh - - curl -XGET 'http://localhost:8085/foo' - -.. note:: - The endpoint defined above is accessible using any HTTP verb. More about defining which HTTP verb to be used in - :ref:`http_mocking_method_option`. - -Example of multiple endpoints mock ----------------------------------- - -Using an array of objects under `http` will define multiple endpoints for the mock: +Using an array of objects under `http` will define endpoints for the mock: .. code-block:: yaml :caption: YAML @@ -119,8 +80,8 @@ These endpoints are then accessible through HTTP: .. code-block:: sh - curl -XGET 'http://localhost:8085/foo' - curl -XGET 'http://localhost:8085/bar' + curl -XGET 'http://localhost:8080/foo' + curl -XGET 'http://localhost:8080/bar' ******* Request @@ -134,6 +95,9 @@ Request Definition The `http.request` may either be a string, an object or an array. +Mockservr comes with a **inference** feature, which means, if you do not explicitly define full `request` options +to use, Mockservr will guess it for you. + Basic definition of a Request ----------------------------- @@ -164,7 +128,7 @@ The endpoint is then accessible through HTTP: .. code-block:: sh - curl -XGET 'http://localhost:8085/foo' + curl -XGET 'http://localhost:8080/foo' .. note:: This way to define an endpoint is equal to: @@ -174,7 +138,8 @@ The endpoint is then accessible through HTTP: http: request: - path: '/foo' + - + path: '/foo' response: body: 'Hello World!' @@ -183,9 +148,11 @@ The endpoint is then accessible through HTTP: { "http": { - "request": { - "path": "/foo" - }, + "request": [ + { + "path": "/foo" + } + ], "response": { "body": "Hello World!" } @@ -231,7 +198,36 @@ The endpoint is then accessible through HTTP: .. code-block:: sh - curl -XGET 'http://localhost:8085/foo' + curl -XGET 'http://localhost:8080/foo' + +.. note:: + This way to define an endpoint is equal to: + + .. code-block:: yaml + :caption: YAML + + http: + request: + - + path: '/foo' + response: + body: 'Hello World!' + + .. code-block:: json + :caption: JSON + + { + "http": { + "request": [ + { + "path": "/foo" + } + ], + "response": { + "body": "Hello World!" + } + } + } Defining multiple Request ------------------------- @@ -274,8 +270,8 @@ The endpoint is then available through different HTTP requests: .. code-block:: sh - curl -XGET 'http://localhost:8085/foo' - curl -XGET 'http://localhost:8085/bar' + curl -XGET 'http://localhost:8080/foo' + curl -XGET 'http://localhost:8080/bar' .. _validator: @@ -293,21 +289,27 @@ To perform this, you may use a Validator ; it is an object with two properties: Mockservr comes with a **Validator inference** feature, which means, if you do not explicitly define which Validator to use, Mockservr will guess it for you. -`scalar` Validator +Inference transform rules : + +- `string` will be transform in `equal` Validator +- `number` will be transform in `equal` Validator +- `boolean` will be transform in `equal` Validator +- `array` will be transform in `anyOf` Validator +- `null` will be transform in `object` Validator +- `object` that is not a validator will be transform in `object` Validator + +`equal` Validator ------------------ -The `scalar` Validator performs an exact match between the expected value and the given one. This Validator +The `equal` Validator performs an exact match between the expected value and the given one. This Validator is automatically inferred when the value is a string, a number or a boolean value. -Some syntactic sugar are also available, to alias the `scalar` Validator and make the definition of the endpoints -more clear. As such, the types `string`, `number` and `boolean` are all alias to the `scalar` Validator. - Example ^^^^^^^ -For example, you can use the `scalar` Validator to validate the path. All the following definitions are equals: +For example, you can use the `equal` Validator to validate the method. All the following definitions are equals: -Using the `scalar` Validator +Using the `equal` Validator """""""""""""""""""""""""""" .. code-block:: yaml @@ -315,40 +317,10 @@ Using the `scalar` Validator http: request: - path: - type: 'scalar' - value: '/foo' - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": { - "type": "scalar", - "value": "/foo" - } - }, - "response": { - "body": "Hello World!" - } - } - } - -Using the `string` Validator -"""""""""""""""""""""""""""" - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: - type: 'string' - value: '/foo' + path: '/foo' + method: + type: 'equal' + value: 'GET' response: body: 'Hello World!' @@ -358,9 +330,10 @@ Using the `string` Validator { "http": { "request": { - "path": { - "type": "string", - "value": "/foo" + "path": "/foo", + "method": { + "type": "equal", + "value": "GET" } }, "response": { @@ -377,7 +350,8 @@ Using the Validator inference http: request: - path: '/foo' + path: "/foo" + method: "GET" response: body: 'Hello World!' @@ -387,7 +361,8 @@ Using the Validator inference { "http": { "request": { - "path": "/foo" + "path": "/foo", + "method": "GET", }, "response": { "body": "Hello World!" @@ -423,7 +398,7 @@ An example of the `regex` Validator can be is presented in :ref:`http_mocking_me ----------------- The `anyOf` Validator may be used to match one of several given values. Under the hood, Mockservr is performing -Validator inference ; it allows to use scalar values (string, number, ...) in the array. However, it is possible +Validator inference ; it allows to use equals values (string, number, ...) in the array. However, it is possible to use Validators inside the array, giving you the possibility to use regular expression, for example. .. code-block:: yaml @@ -431,14 +406,15 @@ to use Validators inside the array, giving you the possibility to use regular ex http: request: - path: + path: "/foo" + method: type: 'anyOf' value: - - '/foo' - - '/bar' + - 'GET' + - 'POST' - type: 'regex' - value: '/^\/p.*$/' + value: '/^P.*$/' response: body: 'Hello World!' @@ -448,14 +424,15 @@ to use Validators inside the array, giving you the possibility to use regular ex { "http": { "request": { - "path": { + "path": "/foo", + "method": { "type": "anyOf", "value": [ - "/foo", - "/bar", + "GET", + "POST", { "type": "regex", - "value": "/^\/p.*$/" + "value": "/^P.*$/" } ] } @@ -470,15 +447,16 @@ The endpoint is then available through different HTTP requests: .. code-block:: sh - curl -XGET 'http://localhost:8085/foo' - curl -XGET 'http://localhost:8085/bar' - curl -XGET 'http://localhost:8085/plop' + curl -XGET 'http://localhost:8080/foo' + curl -XPOST 'http://localhost:8080/foo' + curl -XPUT 'http://localhost:8080/foo' `object` Validator ------------------ The `object` Validator in itself does not perform any validation. Instead, the value is an object, in which one -or more validators are defined. +or more validators are defined for each object attribute. +Validation of `object` Validator will perform recursively. `typeOf` Validator ------------------ @@ -490,7 +468,8 @@ The `typeOf` Validator validates that the given value corresponds to the expecte http: request: - path: + path: '/foo' + method: type: 'typeof' value: 'string' response: @@ -502,7 +481,8 @@ The `typeOf` Validator validates that the given value corresponds to the expecte { "http": { "request": { - "path": { + "path": "/foo" + "method": { "type": "typeof", "value": "string" } @@ -513,10 +493,11 @@ The `typeOf` Validator validates that the given value corresponds to the expecte } } -The example above will match any incoming request, as path is always a string. +The example above will match any incoming request, as method is always a string. .. note:: As Mockservr is using Javascript, running the `typeOf` validator against `null` won't be working as expected. + Use `object` Validator with `null` value instead. Request Options =============== @@ -526,7 +507,7 @@ Request, it must match positively against all options. The options are defined under the `request` object of an HTTP endpoint. -Each option can be described as a :ref:`validator`, but may also be described as a scalar value, for which Mockservr +Most option can be described as a :ref:`validator`, but may also be described as a scalar value, for which Mockservr will perform validator inference. Defining multiple sets of options for a single Request @@ -574,14 +555,52 @@ Then, the two following HTTP requests will lead to the same response: .. code-block:: sh - curl -XGET 'http://localhost:8085/foo' - curl -XGET 'http://localhost:8085/bar' + curl -XGET 'http://localhost:8080/foo' + curl -XGET 'http://localhost:8080/bar' + +`path` option (required) +------------------------ + +The `path` option defines on which path the endpoint can be reached. +The `path` option matching is powered by path-to-regexp_. + +.. _path-to-regexp: https://github.com/pillarjs/path-to-regexp + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo/:id' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo/:id", + }, + "response": { + "body": "Hello World!" + } + } + } + +The example above is an endpoint reachable on the `/foo/[id]` path of Mockservr (typically `http://localhost:8080`) + +.. code-block:: sh + + curl -XGET 'http://localhost:8080/foo/1' `basepath` option ----------------- The `basepath` option allows to define the base path of the request. It is mainly useful to group requests by their base path in the Mockservr GUI. +`basepath` will concat with `path` option before matching .. code-block:: yaml :caption: YAML @@ -589,7 +608,7 @@ base path in the Mockservr GUI. http: request: basepath: '/foo' - path: '/1' + path: '/:id' response: body: 'Hello World!' @@ -600,7 +619,7 @@ base path in the Mockservr GUI. "http": { "request": { "basepath": "/foo", - "path": "/1" + "path": "/:id" }, "response": { "body": "Hello World!" @@ -608,17 +627,19 @@ base path in the Mockservr GUI. } } +.. code-block:: sh + + curl -XGET 'http://localhost:8080/foo/1' + `body` option ------------- -The `body` option allows you to define what the incoming HTTP request's body must look like. For it to be working, the -`Content-Type` header must be defined as `application/x-www-form-urlencoded` or as `application/json`. +The `body` option allows you to define what the incoming HTTP request's body must look like. For it to be working as an object, the +`Content-Type` header must be defined as `application/x-www-form-urlencoded` or as `application/json`. If not it will be working as string. -All types of validator may be used with the `body` option. - -In case the body is a JSON or a form, it is possible to use an object under `body`. In this case, the keys of the object -will be used to find the corresponding key in the HTTP request's body, and it will be matched against the value specified -at the corresponding key. +All types of :ref:`validator` may be used with the `body` option. +In case the body is a JSON or a form, it is possible to use an object under `body`. +If not defined `body` will match any incoming request. .. code-block:: yaml :caption: YAML @@ -651,10 +672,10 @@ at the corresponding key. } In the above example, the JSON or form body must define two key/value pairs: The first one is `name` and its value -must be "John" (the `string` validator is automatically inferred) ; the second one is `last_name` and its value must +must be "John" (the `equal` validator is automatically inferred) ; the second one is `last_name` and its value must either be "Doe" or "Bar" (the `anyOf` validator is automatically inferred). -The incoming request's body may also be a simple string or any other scalar. +The incoming request's body may also be a simple string or any other scalar then the `equal` validator is automatically inferred. .. code-block:: yaml :caption: YAML @@ -684,10 +705,11 @@ The incoming request's body may also be a simple string or any other scalar. `headers` option ---------------- -The `headers` options allows the control of the incoming HTTP request. This option can only be an object with +The `headers` options allows the control of the incoming HTTP request. **It must be an object** be an object with key/value pairs. The key is the header's name, and the value is the expected value. -The value can be any type of validator, allowing a fine-grain control of the headers. +The value can be any type of :ref:`validator`, allowing a fine-grain control of the headers. +If not defined `headers` will match any incoming request. .. code-block:: yaml :caption: YAML @@ -716,7 +738,7 @@ The value can be any type of validator, allowing a fine-grain control of the hea } In the above example, the endpoint will be triggered in the incoming HTTP request contains a `Content-Type` header -and if its value is either `application/json` or `application/x-www-form-urlencoded`. +and if its value is either `application/json` or `application/x-www-form-urlencoded` (the `anyOf` validator is automatically inferred). `maxCalls` option ---------------- @@ -725,6 +747,7 @@ The `maxCalls` option defines a maximum calls count for a given Request. This gi rate limits, for example. The `maxCalls` option does not provide validator inference, as the only possible value is a plain integer. +If not defined `maxCalls` will match any incoming request. .. code-block:: yaml :caption: YAML @@ -761,6 +784,8 @@ not match it positively against this Request. The `method` option defines which type of HTTP requests will match positively with the endpoint. Apart of the usual HTTP verbs (GET, POST, ...), it is possible to set custom HTTP verbs. +All types of :ref:`validator` may be used with the `method` option. +If not defined `method` will match any incoming request. .. code-block:: yaml :caption: YAML @@ -787,37 +812,7 @@ HTTP verbs (GET, POST, ...), it is possible to set custom HTTP verbs. } } -The Request defined above will match positively against any incoming HTTP request which is a GET or a POST request. d - -`path` option -------------- - -The `path` option defines on which path the endpoint can be reached. - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: '/foo' - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": "/foo", - }, - "response": { - "body": "Hello World!" - } - } - } - -The example above is an endpoint reachable on the `/foo` path of Mockservr (typically `http://localhost:8085`) +The Request defined above will match positively against any incoming HTTP request which is a GET or a POST request (the `anyOf` validator is automatically inferred). .. _http_mocking_query_option: @@ -826,6 +821,7 @@ The example above is an endpoint reachable on the `/foo` path of Mockservr (typi The `query` option defines how the incoming HTTP request's query parameters will be matched. **It must be an object** in which each key/value pair correspond to a query parameter/value. The value in each key/value pair is a :ref:`validator`. +If not defined `query` will match any incoming request. .. code-block:: yaml :caption: YAML @@ -835,7 +831,9 @@ in which each key/value pair correspond to a query parameter/value. The value in path: '/foo' query: action: 'show' - id: 1 + id: + type: 'typeOf' + Value: 'number' response: body: 'Hello World!' @@ -848,7 +846,10 @@ in which each key/value pair correspond to a query parameter/value. The value in "path": "/foo", "query": { "action": "show", - "id": 1 + "id": { + "type": "typeOf", + "value": "number" + } } }, "response": { @@ -857,7 +858,7 @@ in which each key/value pair correspond to a query parameter/value. The value in } } -To match the above Request, the incoming HTTP request must be of the form `/foo?action=show&id=1` +To match the above Request, the incoming HTTP request must be of the form `/foo?action=show&id=3` ******** Response @@ -866,7 +867,7 @@ Response When Mockservr matches an incoming HTTP request to a Request defined in an endpoint, it will send back a HTTP response. The definition of this response lies into the `http.response` object. -It is possible to define several Responses for an endpoint and the way Mockservr should pick the right Response from +It is possible to define several Responses for an endpoint and the way Mockservr should pick one of Responses from the incoming HTTP request. Response Definition @@ -877,7 +878,7 @@ request that has been match successfully to the endpoint. It is also possible to define several possible Responses for a single endpoint. To do so, `http.response` must be an array of objects, each object defining a possible Response. In that case, each object must also contains some options -that will tell Mockservr how to pick the right Response ; otherwise, Mockservr will pick the first Response in the +that will tell Mockservr how to pick the right Response ; otherwise, Mockservr will pick one of Response in the array. Defining a single Response @@ -930,10 +931,10 @@ Response randomly, according to their respective weight. response: - body: 'Hello World!' - weight: 0.5 + weight: 1 - body: "Bye World!" - weight: 0.5 + weight: 1 .. code-block:: json :caption: JSON @@ -946,17 +947,17 @@ Response randomly, according to their respective weight. "response": [ { "body": "Hello World!", - "weight": 0.5 + "weight": 1 }, { "body": "Bye World!", - weight: 0.5 + weight: 1 } ] } } -For the endpoint defined above, Mockservr will pick a random Response ; as both their weights are 0.5, they'll be pick +For the endpoint defined above, Mockservr will pick a random Response ; as both their weights are 1, they'll be pick randomly with equal chances. See :ref:`http_mocking_response_weight_option` Response Options diff --git a/docs/index.rst b/docs/index.rst index 6b028e1..c970447 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,6 +5,7 @@ Mockservr is an API mocking system, allowing to configure endpoints, specifying responses. - YAML or JSON endpoint configuration +- Manage endpoint configuration with API - Ability to use Apache Velocity Template files to dynamically adapt responses to requests parameters - Available under docker image, see dockerhub to be easily integrated into a development / test stack @@ -19,3 +20,4 @@ Summary quickstart http_mocking + API diff --git a/docs/quickstart.rst b/docs/quickstart.rst index e9eedde..888cc75 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -27,9 +27,9 @@ One way of running Mockservr is through Docker. .. code-block:: sh - docker run -dit --name my-mockservr -p 8085:80 -p 4580:4580 -v "$PWD":/usr/src/app/mocks mockservr/mockservr:latest + docker run -p 8080:80 -p 4580:4580 -v /mocks-directory:/usr/src/app/mocks rvip/mockservr -From now, all defined mocks will be accessible through `http://localhost:8085`. +From now, all defined mocks will be accessible through `http://localhost:8088`. .. _quickstart_running_with_docker_compose: @@ -45,11 +45,11 @@ Assuming your stack runs using docker-compose, Mockservr can be easily integrate # ... mockservr: - image: mockservr/mockservr:latest + image: rvip/mockservr volumes: - - ./mocks:/usr/src/app/mocks + - ./mocks-directory:/usr/src/app/mocks ports: - - 8085:80 + - 8088:80 - 4580:4580 -From now on, all defined mocks will be accessible through `http://localhost:8085`. +From now on, all defined mocks will be accessible through `http://localhost:8088`. From b4c6c0d19b708ce99e6603d25e8c3b3bb64164dc Mon Sep 17 00:00:00 2001 From: Quentin Fayet Date: Fri, 24 Aug 2018 10:12:19 +0200 Subject: [PATCH 5/7] Add response options to documentation --- docs/http_mocking.rst | 429 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 392 insertions(+), 37 deletions(-) diff --git a/docs/http_mocking.rst b/docs/http_mocking.rst index 77fb0ad..cec4ee9 100644 --- a/docs/http_mocking.rst +++ b/docs/http_mocking.rst @@ -83,6 +83,138 @@ These endpoints are then accessible through HTTP: curl -XGET 'http://localhost:8080/foo' curl -XGET 'http://localhost:8080/bar' +.. note:: + It is possible to define a single endpoint for a mock, by using an object instead of an array under `http`. + +******** +Endpoint +******** + +An Endpoint is defined as one or more responses that correspond to one or more requests, all of them defined under +`http`. If `http` is an array, then each element is an Endpoint. If `http` is an object, then the object is the only +endpoint of the mock. + +An Endpoint defines at least a `request` and an `response` property. See + +Endpoint Options +================ + +`crossOrigin` option +-------------------- + +The `crossOrigin` option enables cross origin requests on Mockservr. This value can either be a boolean or an object. + +If a boolean is given, it will authorize HTTP `OPTION` requests on the endpoint. + +The default response to the `OPTION` method is the following JSON: + +.. code-block:: json + :caption: JSON + + { + "headers": { + "access-control-allow-credentials": true, + "access-control-allow-headers": "request.headers['access-control-request-headers'] || '*'", + "access-control-allow-methods": "GET,HEAD,POST,PUT,DELETE,CONNECT,OPTIONS,TRACE,PATCH", + "access-control-allow-origin": "*", + "access-control-max-age": 3600 + }, + "body": "" + } + +.. note:: + The value of `access-control-allow-headers` is either equal to the request's `access-control-request-headers` header + if defined or `*` (allowing all headers). + +If `crossOrigin` option is an object, it must be a Response object (see `Response`Response_ for more information about +Response's options). It overrides the default response as defined above. + +.. note:: + All headers defined within the `crossOrigin` options will be present in the response sent by Mockservr to any incoming + HTTP request that matches the endpoint. These headers can be overwritten using the `headers`headers_ option of the + `response` object. + +`maxCalls` option +---------------- + +The `maxCalls` option defines a maximum calls count for a given Endpoint. This gives the possibility to simulate API +rate limits, for example. + +The `maxCalls` option does not provide validator inference, as the only possible value is a plain integer. + +.. code-block:: yaml + :caption: YAML + + http: + maxCalls: 5 + request: + path: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "maxCalls": 5 + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + } + } + +In the above example, the Endpoint is going to be positively matched 5 times. When the 6th call arrives, Mockservr will +not match it positively against this Endpoint. + +`rateLimit` option +------------------ + +The `rateLimit` option may either be a plain integer or an object. If a plain integer, it is the maximum number of +accepted calls on this endpoint within one second. If an object, it must define a `callCount` property which is a plain +integer defining the number of accepted calls and a `interval` property defining the time window in milliseconds in +which the `callCount` lies. + +.. code-block:: yaml + :caption: YAML + + http: + rateLimit: + callCount: 2 + interval: 5000 + request: '/foo' + response: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "rateLimit": { + "callCount": 2, + "interval": 5000 + }, + "request": "/foo", + "response": "Hello World!" + } + } + + +`request` option +---------------- + +More details about the `request` option are availble in `Request`Request_. + +`response` option +----------------- + +More details about the `response` option are available in `Response`Response_. + +.. _Request: + ******* Request ******* @@ -740,43 +872,6 @@ If not defined `headers` will match any incoming request. In the above example, the endpoint will be triggered in the incoming HTTP request contains a `Content-Type` header and if its value is either `application/json` or `application/x-www-form-urlencoded` (the `anyOf` validator is automatically inferred). -`maxCalls` option ----------------- - -The `maxCalls` option defines a maximum calls count for a given Request. This gives the possibility to simulate API -rate limits, for example. - -The `maxCalls` option does not provide validator inference, as the only possible value is a plain integer. -If not defined `maxCalls` will match any incoming request. - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: '/foo' - maxCalls: 5 - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": "/foo", - "headers": 5 - }, - "response": { - "body": "Hello World!" - } - } - } - -In the above example, the Request is going to be positively matched 5 times. When the 6th call arrives, Mockservr will -not match it positively against this Request. - .. _http_mocking_method_option: `method` option @@ -860,6 +955,8 @@ If not defined `query` will match any incoming request. To match the above Request, the incoming HTTP request must be of the form `/foo?action=show&id=3` +.. _Response: + ******** Response ******** @@ -965,6 +1062,264 @@ Response Options .. _http_mocking_response_weight_option: +Response options let you specify what content Mockservr will send as a response to a matching incoming HTTP request. + +`body` option +------------- + +The `body` option lets you specify the body of the response. It must be a string. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello World!" + } + } + } + +`bodyFile` option +----------------- + +The `bodyFile` option lets you specify the path to a file that contain the response to send. The file may be of any +type, which lets you define JSON responses, XML responses, pictures, ... The option is the path where to fetch the +file, relatively to the mock file. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + bodyFile: './responses/foo/response.json' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "bodyFile": "./responses/foo/response.json" + } + } + } + +In the previous examples, the response file must be located in a `responses/foo/` directory from the mock's directory, +within a `response.json` file. + +`delay` option +-------------- + +The `delay` option lets you specify a delay (in ms) or a min-max range of delay (in milliseconds) after which the +response will be sent. + +If the given value is a number, it will be considered as a fix delay. You can also specify an object with a `min` and +a `max` property which will respectively be the minimum and maximum delay time, in milliseconds. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello, World!' + delay: + min: 20 + max: 500 + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello, World!", + "delay": { + "min": 20, + "max": 500 + } + } + } + } + +.. _headers: + +`headers` option +---------------- + +The `headers` option lets you specify the headers sent along with the response. It is an object in which the key/value +pairs correspond the name/value pairs of the headers. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Hello, World!' + headers: + Content-Type: 'text/plain' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Hello, World!", + "headers": { + "Content-Type": "text/plain" + } + } + } + } + +`status` option +--------------- + +The `status` option lets you define the HTTP status code of the response. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + body: 'Not found' + status: 404 + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "body": "Not found", + "status": 404 + } + } + } + +`velocity` option +----------------- + +The `velocity` option is an object with an `enabled` value that is a boolean. It tells mockservr if the value specified +in `response.body` or `response.bodyFile` is an Apache Velocity template file and should be parsed accordingly. + +Velocity templates let you access some of the request's parameters (such as query params and form data) and forge a +tailored response. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + bodyFile: './responses/foo/response.json' + velocity: + enabled: true + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": { + "bodyFile": "./responses/foo/response.json", + "velocity": { + "enabled": true + } + } + } + } + +.. note:: + Mockservr take advantage of the `VelocityJS`VeloctiyJS_ javascript library, which does not implement all Velocity features. + Check out their Github page for more information. + +.. _VelocityJS: https://github.com/shepherdwind/velocity.js + +.. note:: + More information about Apache Velocity template files can be foud on `Apache Velocity Documention`__. + +.. _ApacheVelocityDoc: http://velocity.apache.org/engine/2.0/user-guide.html + +__ ApacheVelocityDoc_ + `weight` option --------------- +In case you define multiple responses for a single Request, the `weight` option lets you put weights on responses so +that the random selection of a response will be biased by this weight. Weight are plain numbers. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + response: + - + body: 'Hello World!' + weight: 10 + - + body: "Bye World!" + weight: 1 + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + }, + "response": [ + { + "body": "Hello World!", + "weight": 10 + }, + { + "body": "Bye World!", + weight: 1 + } + ] + } + } + +In the previous example, the "Hello World!" response will be sent by Mockservr 10 out of 11 times and the "By World!" +response 1 out of 11 times. From 46f9c8f59155c578a0024331be4b266e4eeb9a0f Mon Sep 17 00:00:00 2001 From: Quentin Fayet Date: Fri, 24 Aug 2018 17:02:40 +0200 Subject: [PATCH 6/7] Refine documentation by moving validators in its own file --- docs/http_mocking.rst | 308 +++++++----------------------------------- docs/index.rst | 1 + docs/validators.rst | 224 ++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+), 258 deletions(-) create mode 100644 docs/validators.rst diff --git a/docs/http_mocking.rst b/docs/http_mocking.rst index cec4ee9..96b8d7f 100644 --- a/docs/http_mocking.rst +++ b/docs/http_mocking.rst @@ -94,7 +94,20 @@ An Endpoint is defined as one or more responses that correspond to one or more r `http`. If `http` is an array, then each element is an Endpoint. If `http` is an object, then the object is the only endpoint of the mock. -An Endpoint defines at least a `request` and an `response` property. See +An Endpoint defines at least a `request` and an `response` property. + +Mandatory properties +==================== + +`request` option +---------------- + +More details about the `request` option are availble in :ref:`Request`. + +`response` option +----------------- + +More details about the `response` option are available in :ref:`Response`. Endpoint Options ================ @@ -137,10 +150,8 @@ Response's options). It overrides the default response as defined above. `maxCalls` option ---------------- -The `maxCalls` option defines a maximum calls count for a given Endpoint. This gives the possibility to simulate API -rate limits, for example. - -The `maxCalls` option does not provide validator inference, as the only possible value is a plain integer. +The `maxCalls` option defines a maximum calls count for a given Endpoint. It does not provide validator inference, +as the only possible value is a plain integer. .. code-block:: yaml :caption: YAML @@ -202,16 +213,7 @@ which the `callCount` lies. } } - -`request` option ----------------- - -More details about the `request` option are availble in `Request`Request_. - -`response` option ------------------ - -More details about the `response` option are available in `Response`Response_. +In the above example, the API has a rate limit of 2 calls every 5 seconds. .. _Request: @@ -291,17 +293,11 @@ The endpoint is then accessible through HTTP: } } -.. note:: - If you intend to use more specific definition of the incoming requests, see -:ref:`http_mocking_defining_single_request`. - -.. _http_mocking_defining_single_request: - Defining a single Request ------------------------- -If your endpoint must react to single type of Request, then you can use an object to define it. To learn about all -possible options to define the Request, please see :ref:`http_mocking_request_options`. +If your endpoint must react to a single type of Request, then you can use an object to define it. To learn about all +possible options to define the Request, please see `Requests Options`http_mocking_request_options_. .. code-block:: yaml :caption: YAML @@ -405,232 +401,6 @@ The endpoint is then available through different HTTP requests: curl -XGET 'http://localhost:8080/foo' curl -XGET 'http://localhost:8080/bar' -.. _validator: - -Request Validators -================== - -For an incoming HTTP to match a defined Request, it must be positively matched against all the options defined for the -endpoint in the mock file. - -To perform this, you may use a Validator ; it is an object with two properties: - -- `type` which defines the type of Validator to use -- `value` which is the expected value used by the Validator. - -Mockservr comes with a **Validator inference** feature, which means, if you do not explicitly define which Validator -to use, Mockservr will guess it for you. - -Inference transform rules : - -- `string` will be transform in `equal` Validator -- `number` will be transform in `equal` Validator -- `boolean` will be transform in `equal` Validator -- `array` will be transform in `anyOf` Validator -- `null` will be transform in `object` Validator -- `object` that is not a validator will be transform in `object` Validator - -`equal` Validator ------------------- - -The `equal` Validator performs an exact match between the expected value and the given one. This Validator -is automatically inferred when the value is a string, a number or a boolean value. - -Example -^^^^^^^ - -For example, you can use the `equal` Validator to validate the method. All the following definitions are equals: - -Using the `equal` Validator -"""""""""""""""""""""""""""" - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: '/foo' - method: - type: 'equal' - value: 'GET' - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": "/foo", - "method": { - "type": "equal", - "value": "GET" - } - }, - "response": { - "body": "Hello World!" - } - } - } - -Using the Validator inference -""""""""""""""""""""""""""""" - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: "/foo" - method: "GET" - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": "/foo", - "method": "GET", - }, - "response": { - "body": "Hello World!" - } - } - } - -`range` Validator ------------------ - -The `range` Validator may be used to define a range in which the given value should lie. The `value` is an object -composed of two entries: - -- `min`: The lower bound of the range (inclusive) -- `max`: The upper bound of the range (inclusive) - -Both ranges must be numbers (either integer or floats). An example of the `range` Validator can be is presented in -:ref:`http_mocking_query_option`. - -`regex` Validator ------------------ - -The `regex` Validator may be used to match a given value against a regular expression. As such, the `value` entry -is the given regular expression. References about Javascript Regular Expressions can be found on Mozilla_. - -.. _Mozilla: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions - -An example of the `regex` Validator can be is presented in :ref:`http_mocking_method_option`. - -.. _http_mocking_request_options: - -`anyOf` Validator ------------------ - -The `anyOf` Validator may be used to match one of several given values. Under the hood, Mockservr is performing -Validator inference ; it allows to use equals values (string, number, ...) in the array. However, it is possible -to use Validators inside the array, giving you the possibility to use regular expression, for example. - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: "/foo" - method: - type: 'anyOf' - value: - - 'GET' - - 'POST' - - - type: 'regex' - value: '/^P.*$/' - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": "/foo", - "method": { - "type": "anyOf", - "value": [ - "GET", - "POST", - { - "type": "regex", - "value": "/^P.*$/" - } - ] - } - }, - "response": { - "body": "Hello World!" - } - } - } - -The endpoint is then available through different HTTP requests: - -.. code-block:: sh - - curl -XGET 'http://localhost:8080/foo' - curl -XPOST 'http://localhost:8080/foo' - curl -XPUT 'http://localhost:8080/foo' - -`object` Validator ------------------- - -The `object` Validator in itself does not perform any validation. Instead, the value is an object, in which one -or more validators are defined for each object attribute. -Validation of `object` Validator will perform recursively. - -`typeOf` Validator ------------------- - -The `typeOf` Validator validates that the given value corresponds to the expected type. - -.. code-block:: yaml - :caption: YAML - - http: - request: - path: '/foo' - method: - type: 'typeof' - value: 'string' - response: - body: 'Hello World!' - -.. code-block:: json - :caption: JSON - - { - "http": { - "request": { - "path": "/foo" - "method": { - "type": "typeof", - "value": "string" - } - }, - "response": { - "body": "Hello World!" - } - } - } - -The example above will match any incoming request, as method is always a string. - -.. note:: - As Mockservr is using Javascript, running the `typeOf` validator against `null` won't be working as expected. - Use `object` Validator with `null` value instead. - Request Options =============== @@ -840,8 +610,8 @@ The incoming request's body may also be a simple string or any other scalar then The `headers` options allows the control of the incoming HTTP request. **It must be an object** be an object with key/value pairs. The key is the header's name, and the value is the expected value. -The value can be any type of :ref:`validator`, allowing a fine-grain control of the headers. -If not defined `headers` will match any incoming request. +Each object's property value can be any type of :ref:`validator`, allowing a fine-grain control of the headers. +If not defined `headers`, will match any incoming request. .. code-block:: yaml :caption: YAML @@ -870,7 +640,8 @@ If not defined `headers` will match any incoming request. } In the above example, the endpoint will be triggered in the incoming HTTP request contains a `Content-Type` header -and if its value is either `application/json` or `application/x-www-form-urlencoded` (the `anyOf` validator is automatically inferred). +and if its value is either `application/json` or `application/x-www-form-urlencoded` (the `anyOf` validator is +automatically inferred). .. _http_mocking_method_option: @@ -879,8 +650,9 @@ and if its value is either `application/json` or `application/x-www-form-urlenco The `method` option defines which type of HTTP requests will match positively with the endpoint. Apart of the usual HTTP verbs (GET, POST, ...), it is possible to set custom HTTP verbs. -All types of :ref:`validator` may be used with the `method` option. -If not defined `method` will match any incoming request. + +Each object's property value can be any type of :ref:`validator`, allowing a fine-grain control of the incoming query +parameters. If not defined, `query` will match any incoming request. .. code-block:: yaml :caption: YAML @@ -907,7 +679,8 @@ If not defined `method` will match any incoming request. } } -The Request defined above will match positively against any incoming HTTP request which is a GET or a POST request (the `anyOf` validator is automatically inferred). +The Request defined above will match positively against any incoming HTTP request which is a GET or a POST request (the +`anyOf` validator is automatically inferred). .. _http_mocking_query_option: @@ -915,7 +688,9 @@ The Request defined above will match positively against any incoming HTTP reques -------------- The `query` option defines how the incoming HTTP request's query parameters will be matched. **It must be an object** -in which each key/value pair correspond to a query parameter/value. The value in each key/value pair is a :ref:`validator`. +in which each key/value pair correspond to a query parameter/value. + +The value in each key/value pair is a :ref:`validator`. If not defined `query` will match any incoming request. .. code-block:: yaml @@ -1055,7 +830,9 @@ Response randomly, according to their respective weight. } For the endpoint defined above, Mockservr will pick a random Response ; as both their weights are 1, they'll be pick -randomly with equal chances. See :ref:`http_mocking_response_weight_option` +randomly with equal chances. See http_mocking_response_weight_option_. + +.. _http_mocking_request_options: Response Options ================ @@ -1125,6 +902,10 @@ file, relatively to the mock file. In the previous examples, the response file must be located in a `responses/foo/` directory from the mock's directory, within a `response.json` file. +.. note:: + For pictures, only the following mime types are allowed: `image/gif`, `image/jpeg`, `image/pjpeg`, `image/x-png`, + `image/png`, `image/svg+xml`. + `delay` option -------------- @@ -1233,9 +1014,13 @@ The `status` option lets you define the HTTP status code of the response. `velocity` option ----------------- -The `velocity` option is an object with an `enabled` value that is a boolean. It tells mockservr if the value specified +The `velocity` option either a boolean or an object. If a boolean, it tells mockservr if the value specified in `response.body` or `response.bodyFile` is an Apache Velocity template file and should be parsed accordingly. +If an object, it may define an `enabled` value which tells mockservr if it should parse the response body as a Apache +Velocity template file. It may also define a `context` value which is an object. The values in this object will then +be passed to the Velocity engine and thus be available in the Apache Velcity template file. + Velocity templates let you access some of the request's parameters (such as query params and form data) and forge a tailored response. @@ -1280,6 +1065,13 @@ tailored response. __ ApacheVelocityDoc_ +.. note:: + From within the Apache Velocity template, the following objects are available: + - a `math` object which is a Javascript `Math` object + - a `req` object which contains all data from the incoming HTTP request + - an `endpoint` which is the object representing the matched endpoint from the mock definition file + - a `context` which is the optional `velocity.context` object defined above + `weight` option --------------- diff --git a/docs/index.rst b/docs/index.rst index c970447..e9cecbc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,4 +20,5 @@ Summary quickstart http_mocking + validators API diff --git a/docs/validators.rst b/docs/validators.rst new file mode 100644 index 0000000..a1ab167 --- /dev/null +++ b/docs/validators.rst @@ -0,0 +1,224 @@ +.. _validator: + +========== +Validators +========== + +For an incoming HTTP to match a defined Request, it must be positively matched against all the options defined for the +endpoint in the mock file. + +To perform this, you may use a Validator ; it is an object with two properties: + +- `type` which defines the type of Validator to use +- `value` which is the expected value used by the Validator. + +Mockservr comes with a **Validator inference** feature, which means, if you do not explicitly define which Validator +to use, Mockservr will guess it for you. + +Inference transform rules : + +- `string` will be transform in `equal` Validator +- `number` will be transform in `equal` Validator +- `boolean` will be transform in `equal` Validator +- `array` will be transform in `anyOf` Validator +- `null` will be transform in `object` Validator +- `object` that is not a validator will be transform in `object` Validator + +`equal` Validator +------------------ + +The `equal` Validator performs an exact match between the expected value and the given one. This Validator +is automatically inferred when the value is a string, a number or a boolean value. + +Example +^^^^^^^ + +For example, you can use the `equal` Validator to validate the method. All the following definitions are equals: + +Using the `equal` Validator +"""""""""""""""""""""""""""" + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + method: + type: 'equal' + value: 'GET' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "method": { + "type": "equal", + "value": "GET" + } + }, + "response": { + "body": "Hello World!" + } + } + } + +Using the Validator inference +""""""""""""""""""""""""""""" + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: "/foo" + method: "GET" + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "method": "GET", + }, + "response": { + "body": "Hello World!" + } + } + } + +`range` Validator +----------------- + +The `range` Validator may be used to define a range in which the given value should lie. The `value` is an object +composed of two entries: + +- `min`: The lower bound of the range (inclusive) +- `max`: The upper bound of the range (inclusive) + +Both ranges must be numbers (either integer or floats). An example of the `range` Validator can be is presented in +:ref:`http_mocking_query_option`. + +`regex` Validator +----------------- + +The `regex` Validator may be used to match a given value against a regular expression. As such, the `value` entry +is the given regular expression. References about Javascript Regular Expressions can be found on Mozilla_. + +.. _Mozilla: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + +An example of the `regex` Validator can be is presented in :ref:`http_mocking_method_option`. + +`anyOf` Validator +----------------- + +The `anyOf` Validator may be used to match one of several given values. Under the hood, Mockservr is performing +Validator inference ; it allows to use equals values (string, number, ...) in the array. However, it is possible +to use Validators inside the array, giving you the possibility to use regular expression, for example. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: "/foo" + method: + type: 'anyOf' + value: + - 'GET' + - 'POST' + - + type: 'regex' + value: '/^P.*$/' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo", + "method": { + "type": "anyOf", + "value": [ + "GET", + "POST", + { + "type": "regex", + "value": "/^P.*$/" + } + ] + } + }, + "response": { + "body": "Hello World!" + } + } + } + + The endpoint is then available through different HTTP requests: + +.. code-block:: sh + + curl -XGET 'http://localhost:8080/foo' + curl -XPOST 'http://localhost:8080/foo' + curl -XPUT 'http://localhost:8080/foo' + +`object` Validator +------------------ + +The `object` Validator in itself does not perform any validation. Instead, the value is an object, in which one +or more validators are defined for each object attribute. +Validation of `object` Validator will perform recursively. + +`typeOf` Validator +------------------ + +The `typeOf` Validator validates that the given value corresponds to the expected type. + +.. code-block:: yaml + :caption: YAML + + http: + request: + path: '/foo' + method: + type: 'typeof' + value: 'string' + response: + body: 'Hello World!' + +.. code-block:: json + :caption: JSON + + { + "http": { + "request": { + "path": "/foo" + "method": { + "type": "typeof", + "value": "string" + } + }, + "response": { + "body": "Hello World!" + } + } + } + + The example above will match any incoming request, as method is always a string. + +.. note:: +As Mockservr is using Javascript, running the `typeOf` validator against `null` won't be working as expected. + Use `object` Validator with `null` value instead. From 9ba2961e9758e79eb05ec737c55df19a0cd9a550 Mon Sep 17 00:00:00 2001 From: Quentin Fayet Date: Fri, 31 Aug 2018 14:02:42 +0200 Subject: [PATCH 7/7] Add documentation about API --- docs/API.rst | 53 +++++++++++++++++++++++++++++++++++++++++++ docs/http_mocking.rst | 8 +++++++ 2 files changed, 61 insertions(+) diff --git a/docs/API.rst b/docs/API.rst index 88b1428..09aa6b7 100644 --- a/docs/API.rst +++ b/docs/API.rst @@ -3,3 +3,56 @@ === API === + +Mockservr exposes an HTTP API which allow to get information about current endpoints, and to update them if needed. +This API is available through HTTP queries on `http://localhost:4580` (the API is exposed through the port 4580 of +the Mockservr's container). + +------------- +API Endpoints +------------- + +All endpoints are JSON endpoints (`Content-Type: application/json`) and must be prefixed with `/api`. + +`/api` endpoint +=============== + +`GET` method +~~~~~~~~~~~~ + +The response is an object with a single attribute `httpEndpoints`, it contains the number of endpoints currently served +by Mockservr. + +`/api/http-endpoints` endpoint +============================== + +`GET` Method +~~~~~~~~~~~~ + +The response is a collection of all HTTP endpoints cuurrently served by Mockservr. The response includes the internal +ID of the endpoint and the source (mock file or API). + +`POST` method +~~~~~~~~~~~~~ + +It expects a JSON body as defined in :ref:`http_mocking`, defining an endpoint with a Request and a Response. + +The response contains the newly created endpoint with its ID and source. If any error occurred, the response is an +HTTP 400 response with a json object that contains all encountered errors. + +`/api/http-endpoints/:id` endpoint +================================== + +`GET` Method +~~~~~~~~~~~~ + +The response is an object defining the endpoint corresponding to the given `:id`. + +`DELETE` method +~~~~~~~~~~~~~ + +Deletes the endpoint from Mockservr. The response is an HTTP 204 response. If any error occurred, the response is an +HTTP 400 response with a json object that contains all encountered errors. + +.. note:: + `DELETE` method does not delete the mock file, if the target endpoint is defined in a mock file. diff --git a/docs/http_mocking.rst b/docs/http_mocking.rst index 96b8d7f..d31995e 100644 --- a/docs/http_mocking.rst +++ b/docs/http_mocking.rst @@ -1,3 +1,5 @@ +.. _http_mocking: + ============ HTTP Mocking ============ @@ -215,6 +217,9 @@ which the `callCount` lies. In the above example, the API has a rate limit of 2 calls every 5 seconds. +.. note:: + It is possible to add a custom Response in the `html.rateLimit` object. + .. _Request: ******* @@ -1072,6 +1077,9 @@ __ ApacheVelocityDoc_ - an `endpoint` which is the object representing the matched endpoint from the mock definition file - a `context` which is the optional `velocity.context` object defined above + The `endpoint` object contains the parameters that were matched against the incoming HTTP request. It also contains + information about how the parameter was matched (e.g: boolean or regex's capturing group). + `weight` option ---------------