This is a HTTP stub server for integration test with external APIs.
Key features:
- Single JAR
- Declarative API definition using YAML
- Template rendering and pattern matching using Groovy
- File watcher
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: BarRun 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/httpstubYou 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: falseSpecify 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.
- GET
- HEAD
- POST
- PUT
- PATCH
- DELETE
- OPTIONS
- TRACE
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 GMTYou 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: AliceIf 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.jpgFollowing values are parsed as a Groovy template:
- Response header value
- Response body (
body) - Response filename (
file) - Table key (
keyoftables)
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: 3The 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: 1Send 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.