little cubes

Postman is Dead. Long live Bruno

Integrate example requests into your normal development workflow

What’s the biggest problem with Postman?

Section titled: What’s the biggest problem with Postman?

I implore you, dear reader, to take a second and decide what you think the answer to that is.

.

.

.

.

.

.

.

.

.

.

.

.

.

For me, there’s a clear answer.

Postman is an afterthought. It might get updated, it probably won’t. There’s no visibility for anyone else into whether it got updated.

401 Unauthorized - The client secret supplied for a confidential client is invalid



Our entire development workflow is based around the code review process.

Is there a way that postman requests could be code reviewed?

Section titled: Is there a way that postman requests could be code reviewed?

Postman has created proprietary version control and pull request custom mechanisms inside their app.

However:

  • This process is unfamiliar and very much outside of the normal code review process
  • Collections are still reviewed single JSON file
  • In reality, this is going to cause versioning to be defacto controlled manually by one person managing your workspace, rather than being owned by the team through standardized processes.

Is there a way Postman requests could be reviewed alongside your source code?

Section titled: Is there a way Postman requests could be reviewed alongside your source code?

You can export postman requests to JSON.

So you could export requests to json, add them to version control, and pull request those changes. Others would then have to manually import your updated postman json into their postman to see the updates, and the cycle continues.

This process would be exceptionally annoying:

  • Code reviewing JSON isn’t ideal, and one giant JSON blob even less so
  • “pulling” others’ changes involves a lot of manual labor for every change

Introducing, Bruno:

Bruno: Reinventing the API Client

  • Bruno has a familiar UI

    • There are a handful of “postman like” apps and they all pretty much look the same. Bruno is no different, not re-inventing the UI wheel
    • It is not quite as polished as Postman (Postman had a 12 year head start), but it has the most important features and is under continuous development. They publish their roadmap.
  • Everything is saved onto your file system
    • 🔑   This is the key innovation that makes Bruno fundamentally superior to Postman
    • Bruno requests live inside the same git repo that your code lives in
    • Bruno updates are included in the same PR as the corresponding source changes
      • This allows reviewers to ensure that these updates happen simultaneously (just like updating tests)
      • You can create AI rules or a GitHub action to require that Bruno requests get updated when API endpoints are modified.
    • Mass updates to multiple requests are much easier to do via the file system than in a UI
    • Bruno uses a custom human readable “language”, (a la applescript, coffeescript, yaml) that makes PR reviews very natural (as compared to say, a big json file).


  1. Export collection from postman
  2. Import collection into bruno
  3. Clean up your mess of a Postman collection that you never realized was so bad because there was no team ownership over it

Don’t use the environment variable “Secret” checkbox

Section titled: Don’t use the environment variable “Secret” checkbox
  • The checkbox keeps the secret out of source but also prevents you from having any way of sharing it with other devs
  • Instead, distribute secrets the same way we do with code – a .env file

Bruno configure environments dialog

  • I like to include a note at the top that provides clarity about what this file is and how to use it; both if you’re viewing it in an IDE or viewing it in a password manager
api-examples/.env
# Put this at: org/integrations-monorepo/integrations-api/api-examples/.env
# This .env file must be placed right next to this file (api-examples/.env) for
# Bruno to work. This file can be found in Password Manager **Secure Note**:
# Forms Admin API Bruno .env file
# INTEG
INTEG_USER_PASSWORD="little secure"
INTEG_USER_OKTA_CLIENT_ID="0o123"
# STAGING
STAGING_USER_PASSWORD="medium secure"
STAGING_USER_OKTA_CLIENT_ID="0o456"
# PROD
PROD_USER_PASSWORD="big secure 1"
PROD_USER_OKTA_CLIENT_ID="0o789"
  • Similar to postman, you can write pre and post response scripts that set runtime variables via the global bru.setVar(name, value) function.
  • You can also write expressions (in the Vars tab) that do the same thing but without code. You just specify the var name and path to the value using the response object.

Name: global_user_token, Expr: res.body.access_token


  • It’s nice to be able to distinguish between static environment variables and dynamic runtime variables (e.g. tokens). I like to do so with the casing of the variable name

    Variable TypeRecommended Casing
    Env variablecamelCase
    Runtime variablesnake_case
  • I like spaces in my request names to make them easy to read in the Bruno UI.
    • But this also puts spaces in the .bru file names.
    • The true request name comes from meta.name, so you can rename the file manually.
    • But every time someone changes it in the Bruno UI it will revert back. So I don’t think the juice is worth the squeeze
  • When you create a new Bruno collection you choose a name for the directory that contains it
  • You could just go with “bruno” but that’s not helpful for people who don’t know what Bruno is
  • So I always go with api-examples