Introducción a Bruno API Client

Bruno es un revolucionario cliente API de código abierto que adopta un enfoque fundamentalmente diferente para el testing y desarrollo de APIs. A diferencia de las herramientas tradicionales basadas en la nube, Bruno almacena colecciones directamente en tu sistema de archivos usando lenguaje de marcado de texto plano, haciéndolo verdaderamente compatible con Git y enfocado en la privacidad. Esta arquitectura basada en archivos elimina el vendor lock-in y permite colaboración fluida a través de sistemas de control de versiones.

Lanzado en 2022, Bruno rápidamente ganó tracción entre desarrolladores frustrados con modelos de precios por suscripción y dependencia de la nube. Es particularmente atractivo para equipos que ya usan flujos de trabajo Git y desarrolladores que valoran la soberanía de datos.

Por Qué Bruno Destaca

Filosofía Central y Ventajas

Arquitectura Offline-First Bruno no requiere sincronización en la nube ni cuentas. Todo se ejecuta localmente:

  • No requiere login
  • Privacidad completa
  • Funciona sin conexión a internet
  • Rápido y responsivo

Flujo de Trabajo Nativo de Git Las colecciones son archivos de texto plano (formato .bru) que se integran perfectamente con Git:

  • Control de versiones incorporado
  • Revisiones de código fáciles para cambios de API
  • Desarrollo basado en branches
  • Resolución de conflictos de merge usando herramientas Git estándar

Open Source y Gratuito Licenciado bajo MIT, Bruno es verdaderamente gratuito sin limitaciones artificiales:

  • Sin tiers pagos ni características premium
  • Desarrollo impulsado por la comunidad
  • Roadmap transparente
  • Arquitectura extensible

Colecciones como Código El formato de archivo .bru es legible por humanos y diseñado para desarrolladores:

meta {
  name: Get User
  type: http
  seq: 1
}

get {
  url: {{base_url}}/api/users/{{user_id}}
}

headers {
  Authorization: Bearer {{token}}
  Content-Type: application/json
}

vars:pre-request {
  user_id: 123
}

tests {
  test("Status code is 200", function() {
    expect(res.status).to.equal(200);
  });

  test("Response has user data", function() {
    expect(res.body).to.have.property('id');
    expect(res.body).to.have.property('name');
  });
}

Comenzando con Bruno

Instalación

Bruno está disponible para todas las plataformas principales:

# macOS (Homebrew)
brew install bruno

# Windows (Chocolatey)
choco install bruno

# Linux (Snap)
snap install bruno

# O descarga desde GitHub releases
# https://github.com/usebruno/bruno/releases

Creando Tu Primera Colección

  1. Crear Nueva Colección: File → New Collection
  2. Elegir Ubicación: Selecciona una carpeta en tu repositorio Git
  3. Agregar Environment: Crea archivos de entorno para diferentes configuraciones
  4. Crear Requests: Clic derecho en colección → New Request

Estructura de Directorio

my-api/
├── bruno.json          # Metadata de colección
├── environments/
│   ├── local.bru
│   ├── staging.bru
│   └── production.bru
└── requests/
    ├── auth/
    │   ├── login.bru
    │   └── refresh.bru
    └── users/
        ├── get-user.bru
        ├── create-user.bru
        └── update-user.bru

Entendiendo el Formato .bru

El formato .bru es intuitivo y expresivo:

meta {
  name: Create User
  type: http
  seq: 2
}

post {
  url: {{base_url}}/api/users
}

headers {
  Authorization: Bearer {{access_token}}
  Content-Type: application/json
}

body:json {
  {
    "name": "{{user_name}}",
    "email": "{{user_email}}",
    "role": "developer"
  }
}

vars:pre-request {
  user_name: John Doe
  user_email: john@example.com
}

script:pre-request {
  // Generar timestamp
  bru.setVar("timestamp", Date.now());

  // Establecer header personalizado
  req.setHeader("X-Request-ID", bru.getVar("request_id"));
}

script:post-response {
  // Guardar user ID para requests subsecuentes
  const userId = res.body.id;
  bru.setEnvVar("created_user_id", userId);

  // Log response time
  console.log("Response time:", res.responseTime, "ms");
}

tests {
  test("User created successfully", function() {
    expect(res.status).to.equal(201);
    expect(res.body.id).to.be.a('number');
  });
}

Gestión de Entornos

Archivos de Entorno

Los entornos de Bruno son archivos .bru simples:

local.bru

vars {
  base_url: http://localhost:3000
  api_key: local-dev-key
  debug: true
}

production.bru

vars {
  base_url: https://api.production.com
  api_key: {{process.env.PROD_API_KEY}}
  rate_limit: 1000
}

Gestión de Secretos

Bruno se integra con variables de entorno del sistema para datos sensibles:

vars {
  database_url: {{process.env.DATABASE_URL}}
  stripe_key: {{process.env.STRIPE_SECRET_KEY}}
}

Esto previene que los secretos sean commiteados a Git mientras se mantiene la funcionalidad.

Características Avanzadas

Scripting y Automatización

Bruno soporta JavaScript en scripts pre-request y post-response:

Pre-Request Script

// Generar firma HMAC
const crypto = require('crypto');
const message = req.getBody();
const secret = bru.getEnvVar('api_secret');
const signature = crypto
  .createHmac('sha256', secret)
  .update(message)
  .digest('hex');

req.setHeader('X-Signature', signature);

Post-Response Script

// Extraer y guardar token de paginación
if (res.body.next_page_token) {
  bru.setVar('page_token', res.body.next_page_token);
}

// Lógica condicional
if (res.status === 401) {
  // Token expirado, trigger refresh
  console.log('Refreshing authentication token...');
}

Framework de Testing Incorporado

Bruno incluye assertions estilo Chai:

tests {
  // Assertions de código de estado
  test("Request successful", function() {
    expect(res.status).to.be.oneOf([200, 201, 204]);
  });

  // Validación de tiempo de respuesta
  test("Response time acceptable", function() {
    expect(res.responseTime).to.be.below(500);
  });

  // Validación de esquema JSON
  test("Valid user object", function() {
    expect(res.body).to.have.all.keys('id', 'name', 'email');
    expect(res.body.id).to.be.a('number');
    expect(res.body.email).to.match(/.+@.+\..+/);
  });

  // Validación de header
  test("Correct content type", function() {
    expect(res.headers['content-type']).to.include('application/json');
  });
}

Colaboración en Colecciones

Flujo de Trabajo Basado en Git

  1. Commitear cambios de API junto con cambios de código
  2. Crear pull requests para modificaciones de API
  3. Revisar cambios usando herramientas Git diff estándar
  4. Conflictos de merge resueltos con editor de texto

Ejemplo de Flujo de Trabajo Git

# Crear feature branch
git checkout -b feature/add-user-endpoints

# Hacer cambios de API en Bruno
# Commitear cambios
git add requests/users/
git commit -m "Add user CRUD endpoints"

# Push y crear PR
git push origin feature/add-user-endpoints

Code Review de Cambios de API

+ post {
+   url: {{base_url}}/api/users
+ }
+
+ body:json {
+   {
+     "name": "{{user_name}}",
+     "email": "{{user_email}}"
+   }
+ }

Migración desde Postman

Proceso de Importación

Bruno soporta importar colecciones Postman. Si estás evaluando diferentes herramientas de testing de API y comparando sus características, la capacidad de importación de Bruno hace que el cambio sea fluido:

  1. Exportar desde Postman: Collection → Export → Collection v2.1
  2. Importar a Bruno: Collection → Import → Select Postman JSON
  3. Revisar mapeo: Verificar variables de entorno y scripts
  4. Ajustar diferencias: Modificar scripts si es necesario

Diferencias Clave a Entender

CaracterísticaPostmanBruno
AlmacenamientoCloudSistema de archivos
FormatoJSON.bru (texto)
SyncAutomáticoGit
PrecioFreemiumGratis
ColaboraciónIncorporadaBasada en Git
ScriptsSandbox PostmanMódulos Node.js
WorkspacesCloud workspacesCarpetas

Migración de Scripts

Script de Postman

pm.environment.set("token", pm.response.json().access_token);
pm.test("Status is 200", () => {
  pm.response.to.have.status(200);
});

Equivalente en Bruno

bru.setEnvVar("token", res.body.access_token);

test("Status is 200", function() {
  expect(res.status).to.equal(200);
});

CLI y Automatización

Bruno CLI

Ejecuta colecciones desde línea de comandos:

# Instalar CLI
npm install -g @usebruno/cli

# Ejecutar colección completa
bru run --collection ./my-api

# Ejecutar carpeta específica
bru run --collection ./my-api --folder users

# Usar entorno específico
bru run --collection ./my-api --env production

# Formatos de output
bru run --collection ./my-api --output junit.xml --format junit

Integración CI/CD

Ejemplo GitHub Actions

name: API Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup 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 --collection ./api-tests --env ci
        env:
          API_KEY: ${{ secrets.API_KEY }}
          BASE_URL: ${{ secrets.BASE_URL }}

      - name: Upload Results
        uses: actions/upload-artifact@v3
        with:
          name: test-results
          path: test-results.xml

Ejemplo GitLab CI

api-tests:
  stage: test
  image: node:18
  script:
    - npm install -g @usebruno/cli
    - bru run --collection ./api-tests --env staging
  variables:
    API_KEY: $STAGING_API_KEY
  artifacts:
    reports:
      junit: test-results.xml

Soporte GraphQL

Bruno maneja requests GraphQL nativamente. Para equipos que trabajan con APIs gRPC, es importante notar que Bruno se enfoca principalmente en REST y GraphQL:

meta {
  name: Get User Posts
  type: graphql
}

post {
  url: {{graphql_endpoint}}
}

body:graphql {
  query GetUserPosts($userId: ID!) {
    user(id: $userId) {
      id
      name
      posts(first: 10) {
        edges {
          node {
            id
            title
            publishedAt
          }
        }
      }
    }
  }
}

body:graphql:vars {
  {
    "userId": "{{user_id}}"
  }
}

headers {
  Authorization: Bearer {{graphql_token}}
}

Mejores Prácticas

Organización de Colecciones

Estructura de Carpetas Lógica

api-collection/
├── 01-authentication/
│   ├── login.bru
│   ├── logout.bru
│   └── refresh-token.bru
├── 02-users/
│   ├── list-users.bru
│   ├── get-user.bru
│   ├── create-user.bru
│   ├── update-user.bru
│   └── delete-user.bru
├── 03-posts/
└── 04-admin/

Convenciones de Nomenclatura

  • Usa nombres descriptivos: create-user.bru no user1.bru
  • Prefijo con números para ordenar: 01-login.bru, 02-get-profile.bru
  • Usa kebab-case para consistencia

Control de Versiones

Configuración .gitignore

# Ignorar overrides locales de entorno
environments/local.bru

# Ignorar archivos temporales
*.tmp
.bruno-cache/

# Mantener tracked
!environments/*.example.bru

Mensajes de Commit Significativos

git commit -m "Add user registration endpoint with validation"
git commit -m "Update auth flow to use refresh tokens"
git commit -m "Fix pagination in list users endpoint"

Seguridad

Variables de Entorno para Secretos

# Production environment
vars {
  base_url: https://api.example.com
  # Nunca hardcodear secretos
  api_key: {{process.env.PROD_API_KEY}}
  db_password: {{process.env.DB_PASSWORD}}
}

Ejemplo Archivo .env (git-ignored)

PROD_API_KEY=sk_live_xxxxxxxxxxxxx
DB_PASSWORD=super_secret_password
STRIPE_KEY=sk_live_xxxxxxxxxxxxx

Solución de Problemas

Problemas Comunes

Colecciones No Cargan

  • Verificar que bruno.json existe en raíz de colección
  • Verificar permisos de archivo
  • Asegurar que archivos .bru usan sintaxis correcta

Variables de Entorno No Resuelven

  • Verificar que el entorno está seleccionado
  • Verificar spelling de nombre de variable
  • Para variables process.env, asegurar que están exportadas

Scripts No Ejecutan

  • Verificar errores de sintaxis JavaScript
  • Verificar que módulos Node.js están disponibles
  • Revisar output de consola para mensajes de error

Optimización de Rendimiento

Colecciones Grandes

  • Dividir en múltiples colecciones
  • Usar organización de carpetas
  • Carga selectiva en CLI

Tiempo de Respuesta

  • Monitorear condiciones de red
  • Verificar configuraciones de timeout
  • Usar connection pooling para requests masivos

Comparación: Bruno vs Competidores

Al elegir un cliente API, vale la pena comparar Bruno contra alternativas como Insomnia REST client:

CaracterísticaBrunoPostmanInsomniaThunder Client
CostoGratisFreemiumFreemiumGratis + Pro
OfflineLimitado
AlmacenamientoArchivos localesCloudHíbridoWorkspace VS Code
Compatible GitExcelentePobreModeradoBueno
ColaboraciónBasada en GitIncorporadaPagoLimitada
Curva de AprendizajeBajaMediaBajaMuy Baja
ExtensibilidadScriptsScripts + AppsPluginsLimitada

Conclusión

Bruno API Client representa un cambio de paradigma en herramientas de testing de API, priorizando flujos de trabajo de desarrollador, propiedad de datos y simplicidad. Su arquitectura basada en archivos se alinea perfectamente con prácticas modernas de desarrollo centradas en Git, haciéndolo una opción ideal para equipos ya cómodos con control de versiones.

La naturaleza open-source asegura transparencia, innovación impulsada por la comunidad y libertad del vendor lock-in. Aunque puede carecer de algunas características avanzadas encontradas en herramientas establecidas como Postman, el enfoque de Bruno en funcionalidad central y experiencia del desarrollador lo hace cada vez más atractivo para equipos que buscan una alternativa liviana y enfocada en privacidad.

Ya sea que estés migrando desde Postman, comenzando de cero con testing de API, o buscando mejor integración con tu flujo de trabajo Git, Bruno ofrece una solución convincente y costo-efectiva que pone a los desarrolladores primero.