Declarative YAML based HTTP stub server for integration test
This is a HTTP stub server for integration test with external APIs.
Key features:
Download the latest release.
Java 11 or later is required.
Define a route as follows:
mkdir -p data
vim data/users.get.yaml
# data/users.get.yaml
- response:
headers:
content-type: application/json
body:
- id: 1
name: Foo
- id: 2
name: Bar
Run the application:
java -jar httpstub.jar
Call the API:
curl -v http://localhost:8080/users
> GET /users HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 16 Nov 2017 06:50:13 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
<
[{"name":"Foo","id":1},{"name":"Bar","id":2}]
The stub will reload YAML files if they have been changed or new one has been created.
Docker image is available on ghcr.io/int128/httpstub
.
docker run -v $PWD/data:/app/data:ro -p 8080:8080 ghcr.io/int128/httpstub
You can write log to a file.
By following option, the stub writes log to logs/spring.log
, rotates when it reaches 10MB and keeps up to 8 files.
See Spring Boot features: Logging for more.
# Command line option
java -jar httpstub.jar --logging.path=logs
# Environment variable
export LOGGING_PATH=logs
java -jar httpstub.jar
The stub shows following log for each request.
2017-12-05 10:44:20.042 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > GET /users
2017-12-05 10:44:20.043 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > Host: localhost:8080
2017-12-05 10:44:20.044 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > User-Agent: curl/7.54.0
2017-12-05 10:44:20.044 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > Accept: */*
2017-12-05 10:44:20.044 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : >
2017-12-05 10:44:20.047 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : < 200 OK
2017-12-05 10:44:20.048 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : < content-type: application/json
2017-12-05 10:44:20.049 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : < x-uuid: 1992cb3d-7bbf-4c2e-aa65-a19fa656f77e
2017-12-05 10:44:20.050 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : <
2017-12-05 10:44:20.050 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : < [{"name":"Foo","id":1},{"name":"Bar","id":2}]
You can turn off logging by creating data/config.yaml
:
logging:
headers: false
body: false
Specify HTTP method in the extension part of filename.
For example, create a route file data/users.post.yaml
for handling POST method.
Following methods are supported.
A braced string in the file path is treated as a path variable.
For example, create /users/{userId}.get.yaml
for handling /users/1
, /users/2
and so on.
You can set pairs of key and value to the headers. The value must be a string and is parsed as a template (see also the later section).
- response:
headers:
content-type: text/plain
x-uuid: "1234567890"
You can set multiple values.
- response:
headers:
set-cookie:
- sessionId=38afes7a8
- id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT
You can serve a text body as follows:
- response:
headers:
content-type: application/xml
body: |
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user>
<id>1</id>
<name>Foo</name>
</user>
</users>
You can serve a JSON body as follows:
- response:
headers:
content-type: application/json
body:
id: 1
name: Alice
If a character set is specified in the content-type
header, the response body is encoded to the character set.
- response:
headers:
content-type: text/plain;charset=Shift_JIS
body: あいうえお
You can serve a file content as follows:
- response:
headers:
content-type: image/jpeg
file: photo.jpg
Following values are parsed as a Groovy template:
body
)file
)key
of tables
)Following variables are available in a script block ${}
.
Variable | Object |
---|---|
path |
Path variables |
headers |
Request headers |
params |
Query parameters |
body |
Request body |
Type of the request body may be one of following:
Content type of request | Type of request body |
---|---|
application/x-www-form-urlencoded |
Map<String, String> |
multipart/form-data |
Map<String, Part> |
application/json and subset |
Map<String, Object> |
application/xml and subset, text/xml and subset |
Map<String, Object> |
text/* |
String |
Otherwise | null |
For example, create /users/{userId}.get.yaml
as following:
- response:
headers:
content-type: application/json
body:
id: ${path.userId}
name: User${path.userId}
The stub will return the following response on the request GET /users/100
:
{
"id": 100,
"name": "User100"
}
A YAML file has one or more rules.
The stub evaluates each when
of all rules and returns the first matched response
.
Here is the example of /numbers.get.yaml
as follows:
- when: params.order == 'desc'
response:
headers:
content-type: application/json
body: [3, 2, 1]
- when: params.order == 'asc'
response:
headers:
content-type: application/json
body: [1, 2, 3]
The stub will return the following response on the request GET /numbers?order=asc
:
[1, 2, 3]
And on the request GET /numbers?order=desc
:
[3, 2, 1]
If the last resort is not defined, the stub will return 404.
Define constants in data/config.yaml
:
constants:
today: "2017-12-01"
You can use constants in a route YAML:
- response:
headers:
content-type: application/json
body:
- id: 1
name: Foo
registeredDate: ${constants.today}
Tables are usuful for data variation testing.
Let’s see the example.
Request condition: path.userId |
Response variable: tables.userName |
Response variable: tables.age |
---|---|---|
1 | Foo | 35 |
2 | Bar | 100 |
3 | Baz | 3 |
Create /users/{userId}.get.yaml
with following rule.
- response:
headers:
content-type: application/json
body:
id: ${path.userId}
name: ${tables.userName}
age: ${tables.age}
tables:
- name: userName
key: path.userId
values:
1: Foo
2: Bar
3: Baz
- name: age
key: path.userId
values:
1: 35
2: 100
3: 3
The stub will return the following response on the request GET /users/1
:
{
"id": 1,
"name": "Foo",
"age": 35
}
And on the request GET /users/2
:
{
"id": 2,
"name": "Bar",
"age": 100
}
Use delay
attribute in milliseconds to simulate network latency.
For example, create /users.post.yaml
as following:
- response:
delay: 500
headers:
content-type: application/json
body:
id: 1
Send the request POST /users
and the stub will return a response after 500 ms.
This is an open source software.
Feel free to open issues and pull requests.