Bruno:API 測試工具的革命,我拒絕雲端同步!

13 分鐘閱讀

Bruno:API 測試工具的革命,我拒絕雲端同步!
Made with Nano Banana 2 by Gemini 3.1 Pro

Bruno 是一款開源的 API 客戶端,撰文時在 GitHub 上累積超過 42,100 顆星。它和 Postman、Insomnia 做的事情一樣,讓開發者測試和管理 API 請求,但在一個根本性的問題上走了完全相反的路,API Collection 的資料存在你的檔案系統裡,用 Git 做版本控制,不需要帳號,不需要雲端同步。這篇文章會拆解 Bruno 的設計選擇、它的 DSL 演化故事,以及我對「工具該不該知道你在做什麼」這個問題的想法。


Bruno Logo


Postman 砍掉本地模式之後

琳 avatar

我以前都是用 Postman 來測試 API

悠奈 avatar
悠奈

Postman 在 2023 年把本地模式砍了
強制你建帳號同步到雲端
Bruno 就是因為這件事誕生的

Bruno 的誕生和 Postman 的一個決策直接相關。2023 年,Postman 關閉了 Scratchpad 功能,也就是本地模式,強制所有使用者建立帳號並將資料同步到雲端伺服器。對於處理內部 API、攜帶敏感 token 的企業開發者來說,這等於是要求他們把 API 端點、認證資訊、測試資料全部交給第三方託管。Insomnia 後來也做了類似的轉向。

Bruno 的 Manifesto 針對這個現象給出了明確的立場,拒絕被迫使用專有版本控制系統來協作 API Collection,拒絕讓 API 請求和回應的細節被同步到雲端。

這個立場在技術社群引起了廣泛共鳴。截至 2026 年 3 月,Bruno 的企業用戶包含 Microsoft、GitHub、Cisco、Oracle、Nike 等。從一個「反 Postman」的替代品,發展成擁有自己設計哲學的獨立工具,Bruno 的成長速度反映了開發者對資料自主權的實際需求。

檔案系統就是資料庫

Bruno 和其他 API 工具最根本的架構差異在於儲存方式。在 Bruno 中,一個 API Collection 就是檔案系統中的一個資料夾,每個 API 請求是一個獨立的純文字檔案

my-collection/
├── bruno.json           # Collection 設定
├── collection.bru       # Collection 層級腳本
├── environments/
│   └── development.bru
├── users/
│   ├── folder.bru
│   ├── create-user.bru
│   └── get-user.bru
└── orders/
    └── create-order.bru

這個設計帶來幾個直接的實務好處。API Collection 可以放在專案的 Git repository 裡,和原始碼一起管理。PR review 時能直接看到 API 請求的變更差異。新加入團隊的成員 clone 倉庫後,就能找到 API 的使用範例,不需要去問「誰有那個 Collection」。

Bruno 的 Manifesto 裡有一段話讓我印象深刻。創辦人 Anoop M D 描述的願景是,開發者 clone 一個倉庫、啟動服務後,用 Bruno 瀏覽 API 使用範例就能開始工作。不再有「Tim 有 payment-api 的 Collection,但他上個月離職了」這種狀況。

我覺得這段話點出了 API 工具雲端化的一個根本矛盾,API 的使用知識不應該被鎖在某個人的帳號裡。當知識和程式碼共存在同一個 repository,它就成為團隊的共有資產,而非個人的私有收藏。

從自製 DSL 到承認「我錯了」

Bruno 最初為了儲存 API 請求,設計了自己的領域特定語言(DSL),叫做 Bru。Bru 語言的語法大致長這樣:

get {
  url: https://api.github.com/users/usebruno
}

headers {
  content-type: application/json
  Authorization: Bearer topsecret
  ~transaction-id: {{transactionId}}
}

其中 ~ 前綴代表該項目已停用。這個設計解決了「如何在純文字中標記啟用和停用狀態」的問題,算是一個巧妙的語法選擇。

Anoop 在 GitHub Discussion #360 中解釋了為什麼要自製 DSL。JSON 不支援多行字串,在需要貼上 API request body 的場景很不方便。YAML 的縮排規則容易導致格式錯誤。他想要一種不需要引號包裹字串、可讀性優先的格式。

但在經歷了兩年的實際使用和三次大幅修改之後,Anoop 在 2026 年 1 月做了一個決定,承認 YAML 才是正確的選擇。Bruno v3.0.0 開始全面支援 YAML 格式。

悠奈 avatar
悠奈

我覺得 Anoop 的這個決定很有意思
花了好幾個月設計 Bru 語言
引入了 Ohm 解析器框架
經歷三次大改版
最後說「YAML 才對」

這個轉向背後有一個比語法偏好更深層的原因,工具生態的力量大於語法設計的優雅。YAML 擁有現成的語法高亮、linting 工具、JSON Schema 驗證、CI/CD pipeline 整合支援。自製 DSL 再怎麼簡潔,都需要從零建立這些配套。

社群裡有人建議過用 JavaScript 來儲存 API 請求:

const meta = { name: 'User Info', type: 'http', seq: 1 }
const get = { url: `${baseUrl}/users/usebruno`, body: null }

這寫法和 Bru 語法一樣簡潔,而且可以直接享有 JavaScript 工具鏈的支援。但 Bruno 最終選擇了 YAML,和 Kubernetes、Docker Compose、GitHub Actions 站在同一邊。YAML 已經是基礎設施描述的事實標準,在這個領域裡,生態系的慣性比語法的美學更有決定性。

OpenCollection:描述「如何使用」的開放規範

Bruno v3 隨著 YAML 遷移,同時推出了 OpenCollection 規範。這是一個由 Bruno 主導的開放規格,定義了 API Collection 的 YAML 結構。

OpenCollection 和 OpenAPI 的定位不同。OpenAPI 定義的是 API 的契約,也就是端點有哪些、接受什麼參數、回傳什麼結構。OpenCollection 定義的是 API 的使用方式,也就是業務工作流程的順序、前置腳本、測試案例、環境變數設定。Bruno 官方的說法是,「OpenAPI 告訴你門的形狀,OpenCollection 教你如何走過去。」

一個 OpenCollection 的 YAML 檔案長這樣:

info:
  name: Create User
  type: http
  seq: 1

http:
  method: POST
  url: https://api.example.com/users
  body:
    type: json
    data: |-
      {
        "name": "John Doe",
        "email": "john@example.com"
      }

runtime:
  scripts:
    - type: tests
      code: |-
        test("should return 201", function() {
          expect(res.status).to.equal(201);
        });

我認為 OpenCollection 能否成功,取決於 Bruno 以外的工具是否也會採用這個規範。如果只有 Bruno 使用,它就只是 Bruno 的檔案格式,而非真正的開放標準。目前這個規範仍處於早期階段,值得持續觀察。

安全模型:工具該不該知道你在做什麼

Bruno 的安全設計有幾個值得注意的層面。

JavaScript 腳本執行採用沙箱機制。預設的 Safe Mode 會隔離檔案系統存取和網路呼叫,腳本無法讀寫磁碟或發起額外的 HTTP 請求。Developer Mode 則開放完整權限,允許載入外部 npm 套件。從 v3.0.0 開始,CLI 工具預設使用 Safe Mode,需要加上 --sandbox=developer 才能切換到 Developer Mode。這個預設值的選擇,意味著在 CI/CD pipeline 中執行的測試如果沒有明確授權,無法存取機器上的其他資源。

秘密管理提供三種策略:Secret Variables(加密儲存在 Collection 中)、.env 檔案(可加入 .gitignore 避免提交),以及整合外部 Secret Manager,包含 AWS Secrets Manager、Azure Key Vault、HashiCorp Vault。測試報告中的秘密值會自動被遮蔽。

Bruno 選擇完全不知道你在做什麼。這和 Postman 的設計方向截然不同。Postman 知道你的 API 端點、你的 token、你的測試資料,因為這些全部同步到它的伺服器。Bruno 的所有資料都留在你的檔案系統上,團隊協作透過 Git 完成,Bruno 的伺服器不參與任何資料傳輸。

從安全的角度看,減少資料暴露面本身就是一種防護策略。如果工具根本不持有你的資料,它就不可能洩漏你的資料。

功能涵蓋範圍

Bruno 支援的通訊協定涵蓋 HTTP/REST、GraphQL(含變數支援)、gRPC(含 Proto 檔案管理和串流)、WebSocket,以及 SOAP。測試方面使用 Chai 斷言函式庫的 JavaScript 語法,也支援不需要寫程式碼的聲明式 Assertions。

CI/CD 整合透過 Bruno CLI(@usebruno/cli)實現,可在 GitHub Actions、Jenkins 等 pipeline 中執行 Collection 測試,產出 JSON、JUnit 或 HTML 格式的報告。

Bruno v3 加入了 AI Agent 整合功能,支援 Cursor、VS Code with GitHub Copilot、Codex、Claude 等工具。根據文件描述,AI Agent 可以從後端原始碼自動產生 Collection、撰寫測試案例、產生 CI/CD pipeline 設定。這個方向反映了 API 工具和 AI Coding Agent 融合的趨勢。

定價與授權

Bruno 的核心功能以 MIT 授權開源,免費版已經涵蓋大部分個人開發者需要的功能。Pro 版每位使用者每月 6 美元(年繳),增加深度 Git 整合 UI(包含 commit、push、branching、merge conflict resolution 的 GUI 操作)和 48 小時支援 SLA。Ultimate 版每位使用者每月 11 美元(年繳),增加 SAML SSO、SCIM 和 24 小時 SLA。

免費版中,Git 操作限於 init、diff、pull、clone 等基礎功能,進階的 commit 和 push GUI 操作需要 Pro 版。但如果習慣使用終端機,免費版搭配 Git CLI 就能完成所有工作,付費版的價值主要在 GUI 層面的便利性,而非功能上的限制

現階段的限制

Bruno 目前還有幾個值得留意的限制。開源版本的 GUI Git 整合停在基礎操作,團隊規模較大時,每個人都需要熟悉 Git CLI 才能順暢協作。OpenCollection 規範仍在早期階段,生態系支援有限。此外,從 Postman 遷移的匯入功能雖然存在,但 Collection 結構的差異可能需要手動調整。

悠奈 avatar
悠奈

研究完 Bruno 之後我的感想是
它做對了一件事
就是把 API Collection 從「應用程式的資料」變成「原始碼的一部分」
聽起來很簡單
但這個選擇改變了整個協作模型

悠奈 avatar
悠奈

至於 Bru 到 YAML 的故事
我覺得最有價值的部分是 Anoop 願意承認自己錯了
在開源專案裡
承認一個投入了兩年心血的設計決策需要被推翻
這需要的勇氣比寫一個新的解析器還多


本文由蘭堂悠奈撰寫