Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rest Bundle Laravel Package

oxidmod/rest-bundle

oxidmod/rest-bundle is a Symfony bundle that simplifies building REST APIs, offering reusable controllers, serialization helpers, and request handling utilities so you can expose clean, consistent JSON endpoints with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish

composer require --dev vendor/package:0.2.4
php artisan vendor:publish --tag=package-config

Pin the exact version — 0.2.x is pre-1.0, so config keys and CLI flags can shift between minors.

Where to look first

  1. The Mutation testing section of the README and the 0.2.4 changelog entry — this is the only behaviour change in this release.
  2. The published config file: mutation settings are almost certainly a nested block with enable/threshold/paths keys.
  3. Your existing phpunit.xml / pest.php — the feature depends on a working coverage driver, so confirm coverage runs before touching mutation config.

First use case (15 minutes)

Run mutation testing against a single, already well-covered class rather than the whole app:

php artisan package:mutation --class="App\\Services\\InvoiceCalculator"
# or the underlying binary if the package only ships a wrapper
vendor/bin/infection --filter=InvoiceCalculator --threads=max

Read two numbers: MSI (all mutants killed) and Covered MSI (mutants in covered code killed). Covered MSI is the one that tells you about assertion quality; plain MSI is dragged down by untested files and is not actionable on day one.

Do not wire this into the default composer test script. It is a separate, slow, opt-in command.

Implementation Patterns

Local inner loop — one class at a time After writing or changing a service class, run mutation testing scoped to that class with --filter (or --git-diff-lines if supported). Full-suite mutation runs are a PR/CI activity; per-class runs are the day-to-day use.

Coverage → mutation → assertion ratchet The practical workflow for new code:

  1. Write the feature and tests.
  2. php artisan test --coverage --min=100 for the happy path.
  3. Run mutation testing on the new class only.
  4. For each escaped mutant, add the missing assertion (boundary, off-by-one, negated condition, removed return).
  5. Re-run with --id=<mutant-id> to confirm the single kill without waiting for the full class again.

Coverage proves lines execute; mutation proves the assertions would fail if the logic changed. Treat step 4 as the actual review of the test, not the implementation.

Triage escaped mutants by category

  • Genuine gap → add assertion. Most common.
  • Equivalent mutant → behaviour is identical; ignore it explicitly rather than deleting the test.
  • Untested/trivial source → exclude the path (DTOs, config, migrations, Blade, form requests).

CI integration

Give mutation testing its own job — never inline it with the unit-test job:

mutation:
  needs: [tests]
  if: github.event_name == 'pull_request'
  runs-on: ubuntu-latest
  steps:
    - uses: shivammathur/setup-php@v2
      with: { php: 8.3, coverage: pcov }
    - run: composer install --no-interaction --prefer-dist
    - run: vendor/bin/infection --threads=max --git-diff-lines --logger-github

Start with --git-diff-lines / changed-files scoping so the job stays under a few minutes, then widen as the baseline stabilises. Publish the log as a build artifact; the HTML/JSON report is what people actually read when a mutant survives.

Gate by ratchet, not by absolute score

Set minMsi slightly below your current measured value and bump it as you fix survivors. A hard 100% gate on day one gets disabled within a week.

Config layering

Keep mutation config environment-aware: strict thresholds locally, lenient-by-default but diff-scoped in CI, and fully disabled in the deployed app (it's a require-dev tool; verify nothing in the service provider registers routes, migrations, or commands that ship to production).

Gotchas and Tips

Mutation testing needs coverage, and coverage needs a driver. PCOV is dramatically faster than Xdebug for this — if mutation runs take 20+ minutes, check xdebug.mode before anything else. Missing/incorrect coverage config produces mutants that are never killed, which looks like a test problem but isn't.

config:cache in CI will bite you. If the package reads settings through Laravel's config repository and your CI runs php artisan config:cache before the mutation step, env-driven thresholds or paths can silently revert to defaults. Run config:clear in that job, or bypass config and use the CLI flags.

Timeouts masquerade as kills. Slow tests (database, HTTP fakes that actually sleep) can time out under parallel workers, and some tools count a timeout as killed. Set an explicit per-test timeout and check the report for a timedOut count — a nonzero value means your MSI is inflated.

Don't chase 100% MSI. Getters, framework glue, __toString, and defensive ?? fallbacks generate mutants that no reasonable test kills. Exclude them in config (ignoreSource / ignore patterns) and accept a covered-MSI target in the 80–90% band for domain code.

Equivalent mutants are permanent. Mark them explicitly with an inline ignore annotation (e.g. @infection-ignore-all) or a config ignore list, with a one-line comment explaining why. Otherwise every future run re-surfaces them and people learn to ignore the report entirely.

Mocks can cause false survivors. A Facade mock returning a fixed value means mutants inside the real collaborator are never exercised. Prefer fakes/real implementations for the units you mutate; save mocks for genuinely external boundaries.

Pre-commit hooks are the wrong place. Full mutation runs belong on PRs. If you want local protection, restrict the hook to changed files with a hard timeout and fail open (warn, don't block).

Pre-1.0 upgrade discipline. 0.2.4 is additive (mutation testing), so no breakage — but treat each 0.2.x bump as potentially config-changing: read the changelog, re-run the publish diff (vendor:publish --force into a scratch dir) and diff the config against yours.

Extension points to hook into before hacking the package. Most mutation tooling exposes custom mutators, custom test-framework adapters, and event/report listeners. If you need project-specific mutant suppression (e.g. generated code, Illuminate attributes), use the ignore-list config or a custom mutator set rather than forking — you'll want those upgrades.

Debugging a suspiciously high score. Run with a single thread and verbose output on one class, then confirm mutants are actually being generated against the file you think — an incorrect source.directories path results in "no mutants" and a vacuous pass.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings