项目作者: int128

项目描述 :
Declarative YAML based HTTP stub server for integration test
高级语言: Java
项目地址: git://github.com/int128/httpstub.git
创建时间: 2017-10-23T01:50:15Z
项目社区:https://github.com/int128/httpstub

开源协议:Apache License 2.0

下载


httpstub build Gradle Status

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

Getting Started

Download the latest release.
Java 11 or later is required.

Define a route as follows:

  1. mkdir -p data
  2. vim data/users.get.yaml
  1. # data/users.get.yaml
  2. - response:
  3. headers:
  4. content-type: application/json
  5. body:
  6. - id: 1
  7. name: Foo
  8. - id: 2
  9. name: Bar

Run the application:

  1. java -jar httpstub.jar

Call the API:

  1. curl -v http://localhost:8080/users
  2. > GET /users HTTP/1.1
  3. > Host: localhost:8080
  4. > User-Agent: curl/7.47.0
  5. > Accept: */*
  6. >
  7. < HTTP/1.1 200 OK
  8. < Date: Thu, 16 Nov 2017 06:50:13 GMT
  9. < Content-Type: application/json
  10. < Transfer-Encoding: chunked
  11. <
  12. [{"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.

  1. docker run -v $PWD/data:/app/data:ro -p 8080:8080 ghcr.io/int128/httpstub

Options

Logging

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.

  1. # Command line option
  2. java -jar httpstub.jar --logging.path=logs
  3. # Environment variable
  4. export LOGGING_PATH=logs
  5. java -jar httpstub.jar

Request and response logging

The stub shows following log for each request.

  1. 2017-12-05 10:44:20.042 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > GET /users
  2. 2017-12-05 10:44:20.043 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > Host: localhost:8080
  3. 2017-12-05 10:44:20.044 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > User-Agent: curl/7.54.0
  4. 2017-12-05 10:44:20.044 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : > Accept: */*
  5. 2017-12-05 10:44:20.044 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : >
  6. 2017-12-05 10:44:20.047 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : < 200 OK
  7. 2017-12-05 10:44:20.048 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : < content-type: application/json
  8. 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
  9. 2017-12-05 10:44:20.050 INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger : <
  10. 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:

  1. logging:
  2. headers: false
  3. body: false

Recipes

HTTP methods

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.

  • GET
  • HEAD
  • POST
  • PUT
  • PATCH
  • DELETE
  • OPTIONS
  • TRACE

Path variables

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.

Response header

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).

  1. - response:
  2. headers:
  3. content-type: text/plain
  4. x-uuid: "1234567890"

You can set multiple values.

  1. - response:
  2. headers:
  3. set-cookie:
  4. - sessionId=38afes7a8
  5. - id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT

Response body

You can serve a text body as follows:

  1. - response:
  2. headers:
  3. content-type: application/xml
  4. body: |
  5. <?xml version="1.0" encoding="UTF-8"?>
  6. <users>
  7. <user>
  8. <id>1</id>
  9. <name>Foo</name>
  10. </user>
  11. </users>

You can serve a JSON body as follows:

  1. - response:
  2. headers:
  3. content-type: application/json
  4. body:
  5. id: 1
  6. name: Alice

If a character set is specified in the content-type header, the response body is encoded to the character set.

  1. - response:
  2. headers:
  3. content-type: text/plain;charset=Shift_JIS
  4. body: あいうえお

You can serve a file content as follows:

  1. - response:
  2. headers:
  3. content-type: image/jpeg
  4. file: photo.jpg

Template

Following values are parsed as a Groovy template:

  • Response header value
  • Response body (body)
  • Response filename (file)
  • Table key (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:

  1. - response:
  2. headers:
  3. content-type: application/json
  4. body:
  5. id: ${path.userId}
  6. name: User${path.userId}

The stub will return the following response on the request GET /users/100:

  1. {
  2. "id": 100,
  3. "name": "User100"
  4. }

Pattern matching

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:

  1. - when: params.order == 'desc'
  2. response:
  3. headers:
  4. content-type: application/json
  5. body: [3, 2, 1]
  6. - when: params.order == 'asc'
  7. response:
  8. headers:
  9. content-type: application/json
  10. body: [1, 2, 3]

The stub will return the following response on the request GET /numbers?order=asc:

  1. [1, 2, 3]

And on the request GET /numbers?order=desc:

  1. [3, 2, 1]

If the last resort is not defined, the stub will return 404.

Constants

Define constants in data/config.yaml:

  1. constants:
  2. today: "2017-12-01"

You can use constants in a route YAML:

  1. - response:
  2. headers:
  3. content-type: application/json
  4. body:
  5. - id: 1
  6. name: Foo
  7. registeredDate: ${constants.today}

Tables

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.

  1. - response:
  2. headers:
  3. content-type: application/json
  4. body:
  5. id: ${path.userId}
  6. name: ${tables.userName}
  7. age: ${tables.age}
  8. tables:
  9. - name: userName
  10. key: path.userId
  11. values:
  12. 1: Foo
  13. 2: Bar
  14. 3: Baz
  15. - name: age
  16. key: path.userId
  17. values:
  18. 1: 35
  19. 2: 100
  20. 3: 3

The stub will return the following response on the request GET /users/1:

  1. {
  2. "id": 1,
  3. "name": "Foo",
  4. "age": 35
  5. }

And on the request GET /users/2:

  1. {
  2. "id": 2,
  3. "name": "Bar",
  4. "age": 100
  5. }

Delay

Use delay attribute in milliseconds to simulate network latency.

For example, create /users.post.yaml as following:

  1. - response:
  2. delay: 500
  3. headers:
  4. content-type: application/json
  5. body:
  6. id: 1

Send the request POST /users and the stub will return a response after 500 ms.

Contributions

This is an open source software.
Feel free to open issues and pull requests.