Bruno: The Postman alternative you are looking for
Postman used to be my favorite API testing tool, but the company’s decision to phase out the final local collection storage feature, Scratchpad, in favor of mandatory cloud services, has changed that.
What is the best Postman alternative?
Finding an alternative means it must satisfy the following requirements:
- Local collection storage
- Git-friendly collection definitions for my team members
- CLI that can invoke collections
- Beautiful desktop GUI
- No forced account login
with a nice-to-have being open-source.
With that in mind, I came across a service that fulfills all the requirements: bruno.
What is Bruno
Bruno is an open-source Postman alternative that aims to provide a seamless offline experience for testing APIs.
It also plays nicely with Git by using a markdown language, Bru, for defining collections.
Installing Bruno
For MacOS users, installing bruno
is easy with brew
:
1brew install bruno
It’s also supported in many other popular package managers:
1# On Windows via Chocolatey
2choco install bruno
3
4# On Windows via Scoop
5scoop bucket add extras
6scoop install bruno
7
8# On Linux via Snap
9snap install bruno
Migrating from Postman
If you’re planning to migrate from Postman to Bruno, there are import options for collections and environments. For me, it was as simple as exporting the collections/environments in JSON format and importing them.
Scripting in Bruno
Like Postman, Bruno offers scripting capabilities for automating your workflow. I do not use this feature in either solution, but there is more information about it in the Bruno documentation.
Using Bruno CLI
In this section, I will use the Cat Fact API as an example collection.
Installing Bruno CLI
Firstly, let’s install the Bruno CLI using npm
:
1npm install -g @usebruno/cli
Define a collection for catfacts
I opened Bruno and created a new collection named Cat Facts API
with a single GET
request named Get Random Fact
.
When creating my collection, Bruno prompted me to select a folder to store my collection in.
That folder had this structure:
1catfacts
2├── Get Random Fact.bru
3├── bruno.json
4└── environments
5 └── production.bru
Get Random Fact.bru
had file contents like this:
1meta {
2 name: Get Random Fact
3 type: http
4 seq: 1
5}
6
7get {
8 url: {{baseUrl}}/fact
9 body: none
10 auth: none
11}
bruno.json
had file contents like this:
1{
2 "version": "1",
3 "name": "Cat Facts API",
4 "type": "collection"
5}
and the production.bru
file looked like this:
1vars {
2 baseUrl: https://catfact.ninja
3}
Invoke a collection from the Bruno CLI
I navigated to the collection folder and ran the following command:
1bru run --env production
Output:
1Running Folder Recursively
2
3Get Random Fact (200 OK) - 177 ms
4
5Requests: 1 passed, 1 total
6Tests: 0 passed, 0 total
7Assertions: 0 passed, 0 total
8Ran all requests - 177 ms
This executes every .bru
file in the folder.
Bruno additionally gives the ability to run single requests:
1bru run Get\ Random\ Fact.bru --env production
Output:
1Running Request
2
3Get Random Fact (200 OK) - 175 ms
4
5Requests: 1 passed, 1 total
6Tests: 0 passed, 0 total
7Assertions: 0 passed, 0 total
8Ran all requests - 175 ms