{"id":15674788,"url":"https://github.com/int128/httpstub","last_synced_at":"2025-03-30T21:32:03.032Z","repository":{"id":38710321,"uuid":"107919440","full_name":"int128/httpstub","owner":"int128","description":"Declarative YAML based HTTP stub server for integration test","archived":true,"fork":false,"pushed_at":"2024-11-08T06:08:23.000Z","size":589,"stargazers_count":14,"open_issues_count":10,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-22T10:40:19.019Z","etag":null,"topics":["groovy","httpstub","java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/int128.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-23T01:50:15.000Z","updated_at":"2024-11-09T06:26:27.000Z","dependencies_parsed_at":"2023-02-01T14:46:19.939Z","dependency_job_id":"b6850373-dd71-4f47-8008-8f49c4e2fbaf","html_url":"https://github.com/int128/httpstub","commit_stats":{"total_commits":197,"total_committers":5,"mean_commits":39.4,"dds":0.3807106598984772,"last_synced_commit":"690d61fbc165471bf081e0816a4948199c028c5f"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/int128%2Fhttpstub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/int128%2Fhttpstub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/int128%2Fhttpstub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/int128%2Fhttpstub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/int128","download_url":"https://codeload.github.com/int128/httpstub/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246385451,"owners_count":20768668,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["groovy","httpstub","java"],"created_at":"2024-10-03T15:50:46.204Z","updated_at":"2025-03-30T21:31:59.727Z","avatar_url":"https://github.com/int128.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# httpstub [![build](https://github.com/int128/httpstub/actions/workflows/build.yaml/badge.svg)](https://github.com/int128/httpstub/actions/workflows/build.yaml) [![Gradle Status](https://gradleupdate.appspot.com/int128/httpstub/status.svg)](https://gradleupdate.appspot.com/int128/httpstub/status)\n\nThis is a HTTP stub server for integration test with external APIs.\n\nKey features:\n\n- Single JAR\n- Declarative API definition using YAML\n- Template rendering and pattern matching using Groovy\n- File watcher\n\n\n## Getting Started\n\nDownload [the latest release](https://github.com/int128/httpstub/releases).\nJava 11 or later is required.\n\nDefine a route as follows:\n\n```sh\nmkdir -p data\nvim data/users.get.yaml\n```\n\n```yaml\n# data/users.get.yaml\n- response:\n    headers:\n      content-type: application/json\n    body:\n      - id: 1\n        name: Foo\n      - id: 2\n        name: Bar\n```\n\nRun the application:\n\n```\njava -jar httpstub.jar\n```\n\nCall the API:\n\n```\ncurl -v http://localhost:8080/users\n\u003e GET /users HTTP/1.1\n\u003e Host: localhost:8080\n\u003e User-Agent: curl/7.47.0\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 200 OK\n\u003c Date: Thu, 16 Nov 2017 06:50:13 GMT\n\u003c Content-Type: application/json\n\u003c Transfer-Encoding: chunked\n\u003c\n[{\"name\":\"Foo\",\"id\":1},{\"name\":\"Bar\",\"id\":2}]\n```\n\nThe stub will reload YAML files if they have been changed or new one has been created.\n\nDocker image is available on [`ghcr.io/int128/httpstub`](https://ghcr.io/int128/httpstub).\n\n```sh\ndocker run -v $PWD/data:/app/data:ro -p 8080:8080 ghcr.io/int128/httpstub\n```\n\n\n## Options\n\n### Logging\n\nYou can write log to a file.\n\nBy following option, the stub writes log to `logs/spring.log`, rotates when it reaches 10MB and keeps up to 8 files.\nSee [Spring Boot features: Logging](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html) for more.\n\n```\n# Command line option\njava -jar httpstub.jar --logging.path=logs\n\n# Environment variable\nexport LOGGING_PATH=logs\njava -jar httpstub.jar\n```\n\n\n### Request and response logging\n\nThe stub shows following log for each request.\n\n```\n2017-12-05 10:44:20.042  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003e GET /users\n2017-12-05 10:44:20.043  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003e Host: localhost:8080\n2017-12-05 10:44:20.044  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003e User-Agent: curl/7.54.0\n2017-12-05 10:44:20.044  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003e Accept: */*\n2017-12-05 10:44:20.044  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003e\n2017-12-05 10:44:20.047  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003c 200 OK\n2017-12-05 10:44:20.048  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003c content-type: application/json\n2017-12-05 10:44:20.049  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003c x-uuid: 1992cb3d-7bbf-4c2e-aa65-a19fa656f77e\n2017-12-05 10:44:20.050  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003c\n2017-12-05 10:44:20.050  INFO 19694 --- [ctor-http-nio-2] o.h.stubyaml.app.RequestResponseLogger   : \u003c [{\"name\":\"Foo\",\"id\":1},{\"name\":\"Bar\",\"id\":2}]\n```\n\nYou can turn off logging by creating `data/config.yaml`:\n\n```yaml\nlogging:\n  headers: false\n  body: false\n```\n\n\n## Recipes\n\n### HTTP methods\n\nSpecify HTTP method in the extension part of filename.\nFor example, create a route file `data/users.post.yaml` for handling POST method.\nFollowing methods are supported.\n\n- GET\n- HEAD\n- POST\n- PUT\n- PATCH\n- DELETE\n- OPTIONS\n- TRACE\n\n\n### Path variables\n\nA braced string in the file path is treated as a path variable.\nFor example, create `/users/{userId}.get.yaml` for handling `/users/1`, `/users/2` and so on.\n\n\n### Response header\n\nYou 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).\n\n```yaml\n- response:\n    headers:\n      content-type: text/plain\n      x-uuid: \"1234567890\"\n```\n\nYou can set multiple values.\n\n```yaml\n- response:\n    headers:\n      set-cookie:\n        - sessionId=38afes7a8\n        - id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT\n```\n\n\n### Response body\n\nYou can serve a text body as follows:\n\n```yaml\n- response:\n    headers:\n      content-type: application/xml\n    body: |\n      \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n      \u003cusers\u003e\n        \u003cuser\u003e\n          \u003cid\u003e1\u003c/id\u003e\n          \u003cname\u003eFoo\u003c/name\u003e\n        \u003c/user\u003e\n      \u003c/users\u003e\n```\n\nYou can serve a JSON body as follows:\n\n```yaml\n- response:\n    headers:\n      content-type: application/json\n    body:\n      id: 1\n      name: Alice\n```\n\nIf a character set is specified in the `content-type` header, the response body is encoded to the character set.\n\n```yaml\n- response:\n    headers:\n      content-type: text/plain;charset=Shift_JIS\n    body: あいうえお\n```\n\nYou can serve a file content as follows:\n\n```yaml\n- response:\n    headers:\n      content-type: image/jpeg\n    file: photo.jpg\n```\n\n\n### Template\n\nFollowing values are parsed as a Groovy template:\n\n- Response header value\n- Response body (`body`)\n- Response filename (`file`)\n- Table key (`key` of `tables`)\n\nFollowing variables are available in a script block `${}`.\n\nVariable    | Object\n------------|-------\n`path`      | Path variables\n`headers`   | Request headers\n`params`    | Query parameters\n`body`      | Request body\n\nType of the request body may be one of following:\n\nContent type of request | Type of request body\n------------------------|---------------------\n`application/x-www-form-urlencoded` | `Map\u003cString, String\u003e`\n`multipart/form-data` | `Map\u003cString, Part\u003e`\n`application/json` and subset | `Map\u003cString, Object\u003e`\n`application/xml` and subset, `text/xml` and subset | `Map\u003cString, Object\u003e`\n`text/*` | `String`\nOtherwise | `null`\n\nFor example, create `/users/{userId}.get.yaml` as following:\n\n```yaml\n- response:\n    headers:\n      content-type: application/json\n    body:\n      id: ${path.userId}\n      name: User${path.userId}\n```\n\nThe stub will return the following response on the request `GET /users/100`:\n\n```json\n{\n  \"id\": 100,\n  \"name\": \"User100\"\n}\n```\n\n\n### Pattern matching\n\nA YAML file has one or more rules.\nThe stub evaluates each `when` of all rules and returns the first matched `response`.\n\nHere is the example of `/numbers.get.yaml` as follows:\n\n```yaml\n- when: params.order == 'desc'\n  response:\n    headers:\n      content-type: application/json\n    body: [3, 2, 1]\n\n- when: params.order == 'asc'\n  response:\n    headers:\n      content-type: application/json\n    body: [1, 2, 3]\n```\n\nThe stub will return the following response on the request `GET /numbers?order=asc`:\n\n```json\n[1, 2, 3]\n```\n\nAnd on the request `GET /numbers?order=desc`:\n\n```json\n[3, 2, 1]\n```\n\nIf the last resort is not defined, the stub will return 404.\n\n\n### Constants\n\nDefine constants in `data/config.yaml`:\n\n```yaml\nconstants:\n  today: \"2017-12-01\"\n```\n\nYou can use constants in a route YAML:\n\n```yaml\n- response:\n    headers:\n      content-type: application/json\n    body:\n      - id: 1\n        name: Foo\n        registeredDate: ${constants.today}\n```\n\n\n### Tables\n\nTables are usuful for data variation testing.\n\nLet's see the example.\n\nRequest condition: `path.userId` | Response variable: `tables.userName` | Response variable: `tables.age`\n---------------------------------|--------------------------------------|--------------------------------\n1 | Foo | 35\n2 | Bar | 100\n3 | Baz | 3\n\nCreate `/users/{userId}.get.yaml` with following rule.\n\n```yaml\n- response:\n    headers:\n      content-type: application/json\n    body:\n      id: ${path.userId}\n      name: ${tables.userName}\n      age: ${tables.age}\n    tables:\n    - name: userName\n      key: path.userId\n      values:\n        1: Foo\n        2: Bar\n        3: Baz\n    - name: age\n      key: path.userId\n      values:\n        1: 35\n        2: 100\n        3: 3\n```\n\nThe stub will return the following response on the request `GET /users/1`:\n\n```json\n{\n  \"id\": 1,\n  \"name\": \"Foo\",\n  \"age\": 35\n}\n```\n\nAnd on the request `GET /users/2`:\n\n```json\n{\n  \"id\": 2,\n  \"name\": \"Bar\",\n  \"age\": 100\n}\n```\n\n\n## Delay\n\nUse `delay` attribute in milliseconds to simulate network latency.\n\nFor example, create `/users.post.yaml` as following:\n\n```yaml\n- response:\n    delay: 500\n    headers:\n      content-type: application/json\n    body:\n      id: 1\n```\n\nSend the request `POST /users` and the stub will return a response after 500 ms.\n\n\n## Contributions\n\nThis is an open source software.\nFeel free to open issues and pull requests.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fint128%2Fhttpstub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fint128%2Fhttpstub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fint128%2Fhttpstub/lists"}