shahghasiadil/laravel-bruno-generator

Generate Bruno API collections from Laravel routes with automatic request body inference and environment support

Maintainers

Package info

github.com/shahghasiadil/laravel-bruno-generator

pkg:composer/shahghasiadil/laravel-bruno-generator

Transparency log

Statistics

Installs: 4 446

Dependents: 0

Suggesters: 0

Stars: 26

Open Issues: 1

v1.0.3 2026-08-19 11:33 UTC

This package is auto-updated.

Last update: 2026-08-19 11:34:55 UTC


README

Latest Version on Packagist Total Downloads

Generate Bruno API collections from Laravel routes.

This package analyzes your Laravel application's routes and generates a ready-to-use Bruno collection, complete with request bodies inferred from FormRequests, authentication configuration, environment files, and more.

Installation

You can install the package via composer:

composer require shahghasiadil/laravel-bruno-generator --dev

Publish the config file:

php artisan vendor:publish --tag=bruno-generator-config

Quick Start

Generate a collection:

php artisan bruno:generate

Default output:

bruno/collections/Laravel-API/

Open that folder in Bruno using Open Collection.

Features

  • One-command generation from Laravel routes
  • FormRequest body inference
  • Route filtering (middleware, prefix, include/exclude)
  • Multiple organization strategies (prefix, controller, tag, none)
  • Auth support (none, bearer, basic, oauth2), with protected routes pointing at a shared collection-level auth block (auth: inherit)
  • Real Bruno path parameters (:id + params:path) and query parameters inferred from FormRequest rules, with example values informed by where() route constraints when present
  • Multi-environment generation (Local, Staging, Production by default)
  • Optional docs, tests, and scripts generation
  • .bru and OpenCollection YAML (.yml) output support
  • Deterministic, git-friendly generated files
  • bruno:check drift detection for CI — regenerates in memory and exits non-zero if the committed collection is out of date

Usage

Common commands

Generate with default settings:

php artisan bruno:generate

Generate YAML output:

php artisan bruno:generate --format=yaml

Generate only API routes protected by Sanctum:

php artisan bruno:generate --api-only --middleware=auth:sanctum

Generate with docs and tests:

php artisan bruno:generate --with-docs --with-tests

Preview without writing files:

php artisan bruno:generate --dry-run

Overwrite existing output:

php artisan bruno:generate --force

Clear generated collection:

php artisan bruno:clear

Clear a custom path:

php artisan bruno:clear path/to/collection --force

Check whether the committed collection has drifted from what your routes currently produce (regenerates in memory, writes nothing, exits non-zero on drift — useful as a CI gate):

php artisan bruno:check

bruno:check accepts the same filtering/format options as bruno:generate (--format, --output, --name, --api-only, --prefix, --exclude-prefix, --middleware, --exclude-middleware, --group-by) so you can check the same slice of routes you'd generate. Add --verbose to list which files would be added, changed, or are orphaned on disk.

All generate options

php artisan bruno:generate \
  --format=bru|yaml \
  --output=path/to/output \
  --name="My API" \
  --api-only \
  --prefix=api/v1 \
  --exclude-prefix=admin \
  --middleware=auth:sanctum \
  --exclude-middleware=web \
  --group-by=prefix|controller|tag|none \
  --with-body-inference \
  --with-tests \
  --with-scripts \
  --with-docs \
  --force \
  --dry-run

Configuration

You can control most behavior through .env:

BRUNO_OUTPUT_PATH=bruno/collections
BRUNO_COLLECTION_NAME="Laravel API"
BRUNO_OUTPUT_FORMAT=bru
BRUNO_GROUP_BY=prefix
BRUNO_INFER_BODY=true
BRUNO_AUTH_MODE=bearer

APP_URL=http://localhost:8000
STAGING_URL=https://staging.example.com
PRODUCTION_URL=https://api.example.com

After publishing, full options are available in config/bruno-generator.php.

Key config sections

  • output_path, collection_name, output_format
  • route_discovery for include/exclude rules
  • organization for grouping and sorting
  • request_generation for body/query/header behavior
  • auth for mode and auth middleware detection
  • environments for generated Bruno environments
  • advanced for docs length, tests, scripts, YAML options, request settings

FormRequest Body Inference

When enabled, request bodies are generated from your FormRequest rules.

Example FormRequest rules:

public function rules(): array
{
    return [
        'name' => 'required|string|max:255',
        'email' => 'required|email',
        'age' => 'integer|min:18',
        'is_active' => 'boolean',
        'tags' => 'array',
        'tags.*' => 'string',
    ];
}

Example generated body:

{
  "name": "Name",
  "email": "user@example.com",
  "age": 18,
  "is_active": true,
  "tags": [""]
}

Nested rules like user.name and user.email are also supported.

Other rules that shape the generated example:

  • in:draft,published,archived uses the first listed value (draft)
  • between:5,20 on an integer/numeric field uses the lower bound (5), same as min:
  • A file or image rule on any field switches the whole request to a multipart-form body instead of JSON

Output Formats

Both output formats are supported:

  • bru (default)
  • yaml

Use command flag:

php artisan bruno:generate --format=yaml

Or environment variable:

BRUNO_OUTPUT_FORMAT=yaml

Environments

By default, the package generates:

  • Local
  • Staging
  • Production

Each environment contains values like baseUrl and authToken and can be switched in Bruno.

You can add custom environments (for example Development, QA, UAT) in config/bruno-generator.php.

Secret variables

Variable names listed in secrets.variable_names (authToken by default) are never written to the generated environment file — Bruno manages their real value separately (OS keychain, or AES256 as a fallback), and you set it through Bruno's environment UI after opening the collection. In .bru output this looks like a name-only vars:secret [...] block; in YAML output the variable gets secret: true and an empty value.

Use the array shape to mark a custom variable as secret, or add a description:

'environments' => [
    'Staging' => [
        'baseUrl' => env('STAGING_URL', 'https://staging.example.com'),
        'apiKey' => [
            'value' => env('STAGING_API_KEY', ''),
            'description' => 'API key issued by the staging gateway',
            'secret' => true,
        ],
    ],
],

Descriptions are a Bruno 4 addition; set bruno_compatibility to v3 to omit them if your collection needs to open in an older Bruno.

Generated Structure

Typical output:

bruno/collections/Laravel-API/
  bruno.json
  environments/
    Local.bru
    Staging.bru
    Production.bru
  api/
    ...requests and folders...

Best Practices

  • Use --dry-run before first full generation
  • Keep route filters explicit in larger projects
  • Commit generated collections to track API changes
  • Keep environment URLs in .env
  • Let authToken (and other secrets) stay a secret variable rather than disabling secret: false — its real value never gets written to disk
  • Run php artisan bruno:check in CI to catch a committed collection that's drifted from the routes it was generated from

Testing

Run tests:

composer test

Run static analysis:

composer analyse

Format code:

composer format

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

If you discover any security-related issues, please email adil.shahghasi@gmail.com.

Credits

License

The MIT License (MIT). Please see License File for more information.