コンテンツにスキップ

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
npmnpm 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
JSONbru run collection --reporter json
HTMLbru run collection --reporter html --output report.html
JUnitbru 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 Issuesgithub.com/usebruno/bruno/issues

ヒントとコツ

  • レビュー用の Git Diff: コレクションはファイルなので、マージ前に git diff を使用して API の変更を確認
  • 環境テンプレート: シークレットなしで構成構造を共有するために .example.json ファイルを作成
  • 再利用可能なスクリプト: 共通のテスト スクリプトを独立した .js ファイルに保存し、参照
  • 変数スコープ: コレクション変数はグローバルに適用; リクエストレベルの変数でオーバーライド
  • パフォーマンス: CI/CD で --failOnError フラグを使用してテスト失敗を早期に検出
  • ドキュメント: // comment syntax を使用して .bru ファイルにコメントを追加
  • バージョン管理: API バージョンをベース URL 変数に含めて、バージョン間の簡単な切り替え