somnambulist/api-bundle
Somnambulist API Bundle provides a lightweight, opinionated foundation for building JSON APIs in Laravel, with conventions for responses, errors, versioning, and middleware to help standardize endpoints and speed development.
somnambulist/api-bundle is a Symfony bundle, not a Laravel package — there is no ServiceProvider, no facade, and no config-publishing. As a Laravel dev you're borrowing the response-building pieces (somnambulist/response-builder, somnambulist/validation, somnambulist/api-problem) and adapting the plumbing yourself.
Minimal steps:
composer require somnambulist/api-bundlebundles.php) — in Laravel you instead manually wire the classes you want: ResponseBuilder, ApiProblemFactory, and the content-negotiation listeners, typically in a small dedicated service provider you write yourself.ApiController semantics — return a transformer result through the response builder rather than response()->json().Where to look first:
src/Controller/ApiController.php — the base controller pattern.src/Response/ — ResponseBuilder and how it composes Fractal transformers + status codes + links.api-problem integration (ApiProblemFactory, exception listeners) — this is the highest-value piece to lift into Laravel because Laravel's default JSON error shape is not RFC 7807.Accept.Transformer-driven responses. The bundle assumes league/fractal transformers. Instead of Eloquent API Resources, you define a transformer class and pass it to the response builder:
return $this->responseBuilder
->item($user, new UserTransformer(), 200)
->build();
Adapt by binding a ResponseBuilder singleton in a Laravel provider and injecting it into controllers — this gives you consistent envelope shape (data/meta/links) across the API.
RFC 7807 problem+json for errors. Wrap ApiProblemFactory and register it inside app/Exceptions/Handler::render() (or Laravel 11+ withExceptions). This is the single most portable, highest-leverage integration: it turns validation errors and thrown exceptions into application/problem+json bodies, which clients consuming your API can parse uniformly.
Validation via somnambulist/validation. The bundle expects a Validator producing a structured error set that the problem factory understands. If you're on Laravel, either (a) keep validation in FormRequest and manually translate ValidationException into a problem+json shape, or (b) adopt somnambulist/validation alongside — but not instead of — FormRequest so you don't lose Laravel's authorization hooks.
Content negotiation. The negotiation listener parses Accept and picks a format. In Laravel you replicate this with a middleware: read Accept, set an api.format request attribute, and have the response builder respect it. Don't rely on Laravel's Accept handling for HAL/JSON variants — it only knows about json.
Documentation. The bundle's docs story is Symfony/Nelmio-centric. In Laravel, use knuckleswtf/scribe or dedoc/scramble and annotate the same transformer output shapes yourself; don't try to port the Nelmio annotations.
Controller organization. Mirror the bundle's ApiController in a base ApiController in your app that handles: negotiation format resolution, problem-factory access, response-builder access, and a helper for paginated collection responses. This keeps individual controllers thin.
Kernel, config/packages/api.yaml) has no Laravel equivalent. Budget time for hand-wiring the listener stack or you'll end up with a half-integrated API where errors are RFC 7807 but successes aren't (or vice versa).Accept header strictness. The negotiation listener rejects unsupported formats with a 406. Laravel's request()->expectsJson() is much looser. If you port the listener, test with real clients (Postman, curl, browsers) — browser Accept strings often break naive parsing.ApiProblemFactory includes a detail field that can leak internal exception messages. Set it to a safe value in production and log the original — this is a common production footgun with any problem+json integration.transform() + includeX() methods; Eloquent resources use toArray(). Don't mix them per-endpoint — pick one and document it, or response envelopes will differ subtly between routes.LengthAwarePaginator maps cleanly only via league/fractal's IlluminatePaginatorAdapter (in the league/fractal package itself, not this bundle). Add this adapter in your provider.ResponseBuilderInterface, ValidatorInterface, etc.), not by firing events. In Laravel, bind your implementations in the container rather than subclassing.{ "data": null } with no error).api-problem and response-builder) rather than depending on the bundle meta-package.How can I help you explore Laravel packages today?