API tester and debugger for your CLI
Find a file
2024-10-20 15:28:53 +02:00
.github/workflows ci: add test and build workflows 2024-10-19 22:30:14 +02:00
src feat: allow expecting result, for testing APIs 2024-10-20 15:28:53 +02:00
.editorconfig chore: initial commit 2023-05-21 18:35:03 +02:00
.gitignore chore: initial commit 2023-05-21 18:35:03 +02:00
.rustfmt.toml chore: initial commit 2023-05-21 18:35:03 +02:00
Cargo.lock fix: preserve discovery order 2024-10-20 05:56:38 +02:00
Cargo.toml chore: bump version 2024-10-20 05:25:50 +02:00
LICENSE chore: licensed under GPLv3 2024-10-19 22:34:44 +02:00
postwoman.toml feat: allow specifying path base, renamed url>path 2024-10-20 15:28:24 +02:00
README.md docs: updated readme.md 2024-10-20 05:19:35 +02:00

PostWoman

Actions Status Crates.io Version Crates.io Downloads (latest version) GitHub last commit GitHub Issues or Pull Requests

A CLI api tester and request builder, totally not born out of frustration from some other tool...

Why

I'd much rather edit my test routes in my text editor as bare config files and fire them via a CLI than fumble around some GUI application.

As an example, most API test tools have features to automatically split down query arguments from a built url. PostWoman doesn't bother, as your editor will most likely offer multi-cursors and search/replace to easily split off query parameters.

While PostWoman will never be as fully featured as other graphical tools, it doesn't need to be to provide a solid API testing framework.

Usage

Install with cargo install postwoman

postwoman expects a postwoman.toml collection in your cwd. A different file or path can be specified with the global -c option.

Use postwoman run <filter> to send requests to all routes in current config matching given filter (regex). Use . as filter to run all.

Examples

A collection can be super simple

[route.test]
url = "https://api.alemi.dev/debug"

But more complex options are available, check out provided postwoman.toml for some (ready to run!) examples.

More complex collection trees can be achieved with include top level field. Includes are idempotent and always resolved relative from parent collection's directory.

include = [
	"other.toml",
	"even/more.toml"
]

Running

Show collection summary

$ postwoman
~@ postwoman/0.3.1
-> postwoman.toml
 + PW_TOKEN=set-me-as-and-environment-variable!
 - healthcheck 	GET 	https://api.alemi.dev/
 - debug 	PUT 	https://api.alemi.dev/debug
 - benchmark 	GET 	https://api.alemi.dev/look/into/the/void
 - notfound 	GET 	https://api.alemi.dev/not-found
 - payload 	POST 	https://api.alemi.dev/debug
 - cookie 	GET 	https://api.alemi.dev/getcookie

Run all endpoints matching . (aka all of them)

$ postwoman run .
~@ postwoman/0.3.1
 : [05:14:47.241122] postwoman.toml::healthcheck 	sending request...
 + [05:14:47.411708] postwoman.toml::healthcheck 	done in 170ms
{
  "example": [
    "https://api.alemi.dev/debug",
    "https://api.alemi.dev/msg",
    "https://api.alemi.dev/mumble/ping"
  ],
  "time": "Sunday, 20-Oct-2024 03:14:47 GMT",
  "up": true
}
 : [05:14:47.411807] postwoman.toml::debug 	sending request...
 + [05:14:47.574391] postwoman.toml::debug 	done in 162ms
/debug?body=json&cache=0
 : [05:14:47.574474] postwoman.toml::benchmark 	sending request...
 + [05:14:47.726527] postwoman.toml::benchmark 	done in 152ms
 : [05:14:47.726605] postwoman.toml::notfound 	sending request...
 + [05:14:47.878922] postwoman.toml::notfound 	done in 152ms
nginx/1.26.2
 : [05:14:47.879000] postwoman.toml::payload 	sending request...
 + [05:14:48.039053] postwoman.toml::payload 	done in 160ms
{
  "body": "{\n\t\"complex\": {\n\t\t\"json\": \"payloads\",\n\t\t\"can\": \"be\",\n\t\t\"expressed\": \"this\",\n\t\t\"way\": true\n\t}\n}",
  "headers": {
    "accept": [
      "*/*"
    ],
    "connection": "close",
    "content-length": "94",
    "user-agent": "postwoman@sample/0.3.1",
    "x-forwarded-proto": "https",
    "x-real-ip": "93.34.149.115",
    "x-real-port": 46945,
    "x-user-agent": "postwoman@sample/0.3.1"
  },
  "method": "POST",
  "path": "/debug",
  "time": 1729394088.0156112,
  "version": "HTTP/1.0"
}
 : [05:14:48.039099] postwoman.toml::cookie 	sending request...
 + [05:14:48.168725] postwoman.toml::cookie 	done in 129ms
SGF2ZSBhIENvb2tpZSE=

Debug a specific route passing --debug:

$ postwoman run notfound --debug
~@ postwoman/0.3.1
 : [05:15:16.960147] postwoman.toml::notfound 	sending request...
 + [05:15:17.120647] postwoman.toml::notfound 	done in 160ms
Response {
    url: "https://api.alemi.dev/not-found",
    status: 404,
    headers: {
        "server": "nginx/1.26.2",
        "date": "Sun, 20 Oct 2024 03:15:17 GMT",
        "content-type": "text/html",
        "content-length": "153",
        "connection": "keep-alive",
        "vary": "Accept-Encoding",
    },
}
Body: <html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.26.2</center>
</body>
</html>