Bruno コマンド
Bruno は、API のテストと開発用に設計された軽量でオープンソースの Git ネイティブ API クライアントです。Postman とは異なり、Bruno はコレクションをプレーンテキストファイル (.bru 形式) として保存し、Git で バージョン管理でき、チーム協業と CI/CD パイプラインに最適です。
インストール
| プラットフォーム | コマンド |
|---|---|
| macOS (Homebrew) | brew install bruno |
| Linux (Snap) | snap install bruno |
| Linux (APT) | sudo apt-get install bruno |
| Windows (Chocolatey) | choco install bruno |
| npm | npm install -g @usebruno/cli |
| ダウンロード | usebruno.com/downloads にアクセス |
使い始める
Bruno GUI を起動
bruno
新しいコレクションを作成
bruno create-collection my-api-collection
既存のコレクションを開く
bruno /path/to/collection
コレクション管理
コレクション構造
Bruno はコレクションをディレクトリと .bru ファイルとして保存します:
my-api-collection/
├── bruno.json # コレクション メタデータ
├── environments/
│ ├── Development.json
│ └── Production.json
├── auth/
│ └── auth.bru
└── users/
├── get-all-users.bru
├── create-user.bru
└── update-user.bru
Postman からインポート
# Bruno GUI で: Import → Postman コレクション JSON を選択
# または CLI を使用 (Bruno のバージョンによって利用可能な場合)
フォルダ内でリクエストを整理
コレクション内にフォルダを作成してリクエストを整理できます:
- コレクション ツリーで右クリック → 新規フォルダ
- フォルダに論理的な名前を付ける (例: users、products、auth)
- フォルダ間でリクエストをドラッグ
コレクションをエクスポート
# コレクションはプレーンファイル (.bru 形式) として保存されます
# Git にコミットするか、ディレクトリを共有するだけです
Bru 言語 (リクエスト形式)
Bruno は .bru ファイルを使用します。これはリクエスト用のシンプルで読みやすいマークアップ言語です。
基本的なリクエスト ファイル
meta {
name: Get All Users
type: http
seq: 1
}
get {
url: {{baseUrl}}/api/users
auth: bearer
}
params:query {
limit: 10
offset: 0
}
headers {
Content-Type: application/json
User-Agent: Bruno/v1
}
auth:bearer {
token: {{authToken}}
}
ボディを含むリクエスト
meta {
name: Create User
type: http
seq: 2
}
post {
url: {{baseUrl}}/api/users
}
headers {
Content-Type: application/json
}
body:json {
{
"name": "John Doe",
"email": "john@example.com",
"role": "admin"
}
}
フォーム データ リクエスト
meta {
name: Upload Profile Picture
type: http
seq: 3
}
post {
url: {{baseUrl}}/api/users/{{userId}}/avatar
}
body:form-urlencoded {
username: johndoe
email: john@example.com
}
フォーム マルチパート (ファイル アップロード)
meta {
name: Upload File
type: http
seq: 4
}
post {
url: {{baseUrl}}/api/files/upload
}
body:multipartForm {
file: @/path/to/file.pdf
description: My document
}
CLI コマンド
コレクションまたはリクエストを実行
# コレクション全体を実行
bru run /path/to/collection
# 特定のリクエストを実行
bru run /path/to/collection/requests/get-users.bru
# 特定の環境で実行
bru run /path/to/collection --env Production
# JSON レポーター形式で実行
bru run /path/to/collection --reporter json
# HTML レポートで実行
bru run /path/to/collection --reporter html --output report.html
利用可能なレポーター
| レポーター | コマンド |
|---|---|
| CLI (デフォルト) | bru run collection --reporter cli |
| JSON | bru run collection --reporter json |
| HTML | bru run collection --reporter html --output report.html |
| JUnit | bru run collection --reporter junit |
変数を使用して実行
# 環境変数を渡す
bru run /path/to/collection --env Development
# 特定の変数をオーバーライド
bru run /path/to/collection --env Production --variable apiKey=abc123
エラーで失敗
# いずれかのテストが失敗した場合、ゼロ以外のステータスで終了 (CI/CD に有用)
bru run /path/to/collection --failOnError
詳細出力
# リクエスト/レスポンスの詳細情報を表示
bru run /path/to/collection --verbose
環境変数
環境ファイルを作成
環境ファイルは environments/EnvName.json として保存されます:
{
"baseUrl": "https://api.example.com",
"apiKey": "your-api-key-here",
"authToken": "bearer-token",
"userId": "12345",
"timeout": 5000
}
リクエストで変数を使用
get {
url: {{baseUrl}}/api/users/{{userId}}
timeout: {{timeout}}
}
headers {
Authorization: Bearer {{authToken}}
X-API-Key: {{apiKey}}
}
環境を切り替え
# CLI 経由
bru run /path/to/collection --env Development
# GUI 経由: Bruno インターフェイスの環境ドロップダウンを選択
環境変数の種類
| 種類 | 例 | 使用法 |
|---|---|---|
| 文字列 | "apiKey": "abc123" | {{apiKey}} |
| 数値 | "timeout": 5000 | {{timeout}} |
| ブール値 | "debug": true | {{debug}} |
| オブジェクト | "config": {...} | スクリプトでアクセス |
シークレット管理
# 機密データ用の .env ファイルを作成 (.gitignore に追加)
echo "PROD_API_KEY=secret123" > .env
# 環境ファイルで参照を使用
# または Bruno の GUI を使用してフィールドを「シークレット」としてマーク
プリ リクエスト スクリプト
リクエストが送信される前に JavaScript を追加:
// 動的な値を設定
bru.setEnvVar('timestamp', Date.now());
bru.setEnvVar('nonce', Math.random().toString(36).substring(7));
// 条件付きロジック
if (bru.getEnvVar('env') === 'production') {
bru.setEnvVar('timeout', 10000);
}
// デバッグ情報をログ
console.log('Sending request to', bru.getEnvVar('baseUrl'));
ポスト レスポンス スクリプト
レスポンスを受け取った後に JavaScript を実行:
// レスポンス データにアクセス
const responseData = res.getBody();
const statusCode = res.getStatus();
const headers = res.getHeaders();
// 次のリクエスト用に値を保存
if (statusCode === 200) {
bru.setEnvVar('authToken', responseData.token);
bru.setEnvVar('userId', responseData.user.id);
}
// レスポンスをログ
console.log('Status:', statusCode);
console.log('Response:', JSON.stringify(responseData, null, 2));
一般的なレスポンス操作
// ステータス コードを取得
const status = res.getStatus();
// ボディを文字列として取得
const body = res.getBody();
// JSON ボディをパース
const data = res.getBody(true); // true = JSON としてパース
// ヘッダーを取得
const contentType = res.getHeader('content-type');
// 特定のヘッダーを取得
const authHeader = res.getHeader('authorization');
アサーションとテスト
組み込みテスト アサーション
// ステータス コード アサーション
tests['Status is 200'] = (res.getStatus() === 200);
// レスポンス ボディに含まれる
tests['Response contains user'] = res.getBody().includes('john');
// JSON レスポンス検証
const data = res.getBody(true);
tests['User ID exists'] = data.user && data.user.id > 0;
// レスポンス時間
tests['Response time < 500ms'] = res.getResponseTime() < 500;
// ヘッダー検証
tests['Content-Type is JSON'] = res.getHeader('content-type').includes('application/json');
複雑なテスト例
const data = res.getBody(true);
tests['Status is 201'] = res.getStatus() === 201;
tests['ID is a number'] = typeof data.id === 'number';
tests['Email is valid'] = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(data.email);
tests['Created at is ISO date'] = !isNaN(Date.parse(data.createdAt));
// 次のリクエスト用に保存
if (tests['Status is 201']) {
bru.setEnvVar('newUserId', data.id);
}
認証
Bearer トークン
auth:bearer {
token: {{authToken}}
}
基本認証
auth:basic {
username: {{username}}
password: {{password}}
}
API キー (ヘッダー)
headers {
X-API-Key: {{apiKey}}
Authorization: ApiKey {{apiKey}}
}
API キー (クエリ パラメータ)
params:query {
api_key: {{apiKey}}
apiToken: {{token}}
}
OAuth 2.0
auth:oauth2 {
grant_type: authorization_code
authorization_url: https://provider.com/oauth/authorize
token_url: https://provider.com/oauth/token
client_id: {{clientId}}
client_secret: {{clientSecret}}
scope: read write
}
Digest 認証
auth:digest {
username: {{username}}
password: {{password}}
}
リクエスト タイプとメソッド
GET リクエスト
meta {
name: Fetch User
type: http
seq: 1
}
get {
url: {{baseUrl}}/api/users/{{userId}}
}
params:query {
includeProfile: true
fields: id,name,email
}
POST リクエスト
post {
url: {{baseUrl}}/api/users
}
body:json {
{
"name": "Jane Doe",
"email": "jane@example.com"
}
}
PUT/PATCH リクエスト
put {
url: {{baseUrl}}/api/users/{{userId}}
}
body:json {
{
"name": "Jane Smith",
"status": "active"
}
}
DELETE リクエスト
delete {
url: {{baseUrl}}/api/users/{{userId}}
}
ヘッダー付きリクエスト
headers {
Content-Type: application/json
Accept: application/json
User-Agent: Bruno/v1.0
X-Request-ID: {{requestId}}
Authorization: Bearer {{token}}
}
高度な機能
コレクションレベルの変数
bruno.json で変数を定義:
{
"name": "My API Collection",
"version": "1.0",
"variables": {
"baseUrl": "https://api.example.com",
"version": "v1",
"defaultTimeout": 5000
}
}
リクエスト シーケンシング
CLI ランナーでリクエスト実行順序を制御:
meta {
name: Authenticate
type: http
seq: 1
}
meta {
name: Get User Data
type: http
seq: 2
}
リクエストは seq 順に実行されます。
GraphQL クエリ
meta {
name: GraphQL Query
type: http
seq: 1
}
post {
url: {{baseUrl}}/graphql
}
body:graphql {
query {
user(id: "{{userId}}") {
id
name
email
}
}
}
クエリ パラメータ
params:query {
page: 1
limit: 10
sort: -createdAt
filter: status:active
}
Git ワークフロー
Git ネイティブが重要な理由
# コレクションはテキスト ファイルとして保存
.bru/
├── users/
│ ├── get-user.bru
│ └── create-user.bru
└── products/
└── list-products.bru
# バージョン管理が簡単
git add .
git commit -m "Update API requests"
git push origin main
# マージ競合は管理可能
# PR で変更を確認
# チームと協業
協業ワークフロー
# チーム メンバーがコレクションをクローン
git clone https://github.com/team/api-collection.git
cd api-collection
# Bruno CLI をインストール
npm install -g @usebruno/cli
# ローカルでテストを実行
bru run . --env Development
# 変更を加える
# 新しいリクエストを追加するか、既存のリクエストを更新
# コミットしてプッシュ
git add .
git commit -m "Add payment API endpoints"
git push origin feature/payments
機密ファイルを無視
# コレクション ルート内の .gitignore
.env
.env.local
environments/Production.json
!environments/Production.json.example
secrets/
node_modules/
CI/CD 統合
GitHub Actions
name: API Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install Bruno CLI
run: npm install -g @usebruno/cli
- name: Run API tests
run: bru run . --env CI --reporter json --output test-results.json
- name: Upload results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-results
path: test-results.json
GitLab CI
api-tests:
image: node:18
script:
- npm install -g @usebruno/cli
- bru run . --env CI --reporter json --output test-results.json
artifacts:
paths:
- test-results.json
reports:
junit: test-results.json
ローカル プリコミット フック
#!/bin/bash
# .git/hooks/pre-commit
echo "Running API tests..."
bru run . --env Development --failOnError
if [ $? -ne 0 ]; then
echo "API tests failed. Commit aborted."
exit 1
fi
一般的なワークフロー
REST API のテスト
# 1. 環境を設定
bru run /path/to/collection --env Development
# 2. テスト結果を確認
# テストの合否が出力に表示されます
# 3. レポートを生成
bru run /path/to/collection --env Development --reporter html --output report.html
並列リクエストを使用した ロード テスト
// プリ リクエスト スクリプト内
for (let i = 0; i < 10; i++) {
bru.setEnvVar('iteration', i);
}
動的データ生成
// リクエストごとに一意のメールを生成
const timestamp = Date.now();
bru.setEnvVar('dynamicEmail', `user_${timestamp}@example.com`);
// ランダム ID を生成
bru.setEnvVar('randomId', Math.floor(Math.random() * 10000));
リクエストをチェーン
// 最初のリクエストのポスト レスポンス スクリプト内
const data = res.getBody(true);
bru.setEnvVar('userId', data.id);
// 次のリクエストは {{userId}} を使用
デバッグ
詳細モードを有効にする
bru run /path/to/collection --verbose
リクエスト/レスポンスの詳細を表示
Bruno GUI では:
- リクエストをクリック
- 「Params」タブを表示してクエリ パラメータを確認
- 「Body」タブを表示してリクエスト ボディを確認
- 「Response」タブを表示してレスポンス データを確認
- 「Tests」タブを表示してテスト結果を確認
コンソール ログ
// プリ リクエストまたはポスト レスポンス スクリプト内
console.log('Variable value:', bru.getEnvVar('baseUrl'));
console.log('Full response:', res.getBody());
console.log('Status code:', res.getStatus());
ネットワーク検査
// レスポンス ヘッダーを確認
const headers = res.getHeaders();
console.log('All headers:', headers);
// レスポンス時間を確認
console.log('Response time:', res.getResponseTime(), 'ms');
ファイル構造のベスト プラクティス
api-collection/
├── README.md # ドキュメント
├── .gitignore # 機密ファイルを無視
├── bruno.json # コレクション メタデータ
├── environments/ # 環境ファイル
│ ├── Development.json
│ ├── Staging.json
│ └── Production.json
├── globals.json # グローバル変数
├── auth/
│ ├── login.bru
│ └── refresh-token.bru
├── users/
│ ├── get-all-users.bru
│ ├── get-user-by-id.bru
│ ├── create-user.bru
│ ├── update-user.bru
│ └── delete-user.bru
├── products/
│ ├── list-products.bru
│ └── get-product.bru
└── scripts/
├── test-runner.js
└── helpers.js
リソース
| リソース | URL |
|---|---|
| 公式 Web サイト | usebruno.com |
| GitHub リポジトリ | github.com/usebruno/bruno |
| ドキュメント | docs.usebruno.com |
| ダウンロード | usebruno.com/downloads |
| Discord コミュニティ | discord.gg/usebruno |
| Bru 言語仕様 | github.com/usebruno/bru |
| API テスト ガイド | docs.usebruno.com/api-testing |
| GitHub Issues | github.com/usebruno/bruno/issues |
ヒントとコツ
- レビュー用の Git Diff: コレクションはファイルなので、マージ前に
git diffを使用して API の変更を確認 - 環境テンプレート: シークレットなしで構成構造を共有するために
.example.jsonファイルを作成 - 再利用可能なスクリプト: 共通のテスト スクリプトを独立した
.jsファイルに保存し、参照 - 変数スコープ: コレクション変数はグローバルに適用; リクエストレベルの変数でオーバーライド
- パフォーマンス: CI/CD で
--failOnErrorフラグを使用してテスト失敗を早期に検出 - ドキュメント:
// comment syntaxを使用して.bruファイルにコメントを追加 - バージョン管理: API バージョンをベース URL 変数に含めて、バージョン間の簡単な切り替え