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

Api Bundle Laravel Package

weblabel/api-bundle

WebLabel API Bundle is a Composer-installable Symfony bundle offering a ready-to-use API layer for WebLabel applications, with routing, serialization, configurable endpoints, and consistent integration patterns that reduce boilerplate and speed delivery.

View on GitHub
Deep Wiki
Context7

Getting Started

weblabel/api-bundle is a small Symfony bundle (not Laravel) that packages the plumbing most REST APIs need and nobody wants to rewrite: a base API controller, JSON response helpers, an exception listener that turns thrown exceptions into consistent JSON error payloads, and helpers around request-body validation. There is essentially no documentation, so treat the source as the spec.

Minimal setup

composer require weblabel/api-bundle

Register it (Symfony Flex may do this; verify):

// config/bundles.php
return [
    // ...
    Weblabel\ApiBundle\WeblabelApiBundle::class => ['all' => true],
];

Check vendor/weblabel/api-bundle/DependencyInjection/Configuration.php for the config root key (usually weblabel_api) and any defaults. In most setups you can run with zero config.

Where to look first, in this order:

  1. Controller/ApiController.php — the class you will extend. Whatever helpers it exposes (respond, respondCreated, respondNoContent, respondError-style methods) become your team's vocabulary.
  2. EventListener/ — the exception listener. This is the highest-value piece: it decides which exception classes map to which HTTP status and what the JSON error envelope looks like.
  3. Exception/ — the typed exceptions you're expected to throw (NotFoundException, BadRequestException, ValidationException, etc.).
  4. README.md — expect one paragraph; don't budget time for it.

First use case — make /api/health return JSON and make a missing entity return 404 application/json instead of Symfony's HTML error page:

namespace App\Controller;

use Weblabel\ApiBundle\Controller\ApiController;
use Weblabel\ApiBundle\Exception\NotFoundException;
use Symfony\Component\Routing\Annotation\Route;

class OrderController extends ApiController
{
    /** @Route("/api/orders/{id}", methods={"GET"}) */
    public function show(int $id)
    {
        $order = $this->getDoctrine()->getRepository(Order::class)->find($id);

        if (!$order) {
            throw new NotFoundException("Order {$id} not found");
        }

        return $this->respond($order, ['groups' => ['order:read']]);
    }
}

If respond() doesn't exist under that name, the base controller almost certainly exposes an equivalent — confirm the signature before writing more than one controller against it.

Implementation Patterns

One resource controller per aggregate, all extending the base controller. This keeps the response envelope and error behaviour uniform. Don't mix in plain AbstractController responses for "just this one endpoint" — clients will see two error shapes.

Throw, don't return errors. The listener pattern only pays off if you commit to it:

if (!$user->isActive()) {
    throw new BadRequestException('Account is inactive');
}

Map your domain exceptions to status codes in one place (typically a getStatusCode() on each exception class, or a match table in the listener). When you add a new exception type, add it to that table and add a test asserting the JSON body.

JSON request bodies. Symfony does not populate $request->request for application/json. Either use the bundle's body-decoding helper if it ships one, or do it explicitly and validate with the Symfony Validator:

$payload = json_decode($request->getContent(), true) ?? [];
$dto = $this->denormalize($payload, CreateOrderInput::class);

$errors = $this->validator->validate($dto);
if (count($errors) > 0) {
    throw new ValidationException($errors); // → 422 with field-level details
}

Keep DTOs separate from entities. Denormalising straight into Doctrine entities is where most of the security and validation bugs come from.

Serialization groups over hand-built arrays. Use ['groups' => ['order:read']] on the response helper and annotate entities/DTOs. This is the cheapest way to stop leaking password hashes and internal flags, and it gives you a free read/write split.

Pagination envelope. Pick one shape and never deviate:

{ "data": [...], "meta": { "page": 2, "per_page": 25, "total": 1043 } }

If the bundle provides a paginator helper, use it; otherwise a small PaginatedResponse value object keeps controllers to three lines.

Integration tips

Laravel habit Symfony equivalent here
return response()->json($x, 201) base controller respond($x, 201)
abort(404) / ModelNotFoundException throw new NotFoundException()
$request->validate([...]) Validator + ValidationException
API Resources Serializer groups
Handler::render in app/Exceptions/Handler.php kernel.exception listener from this bundle

Testing. Use KernelBrowser / WebTestCase and assert on status + JSON structure, not on exact strings. One test per exception mapping is worth more than ten happy-path tests, because the listener is the piece most likely to silently regress.

Gotchas and Tips

This is a 0-star, 0-dependent, single-release package (last tag 2021-12-08). Pin the exact version in composer.json, and consider copying the handful of classes you actually use into src/Api/ rather than carrying a dependency that will not receive Symfony 7 compatibility. The bundle is small enough that vendoring is realistic; the exception listener is ~100 lines.

JSON bodies are empty in $request->request. Repeating this because it is the #1 bug: use $request->getContent(), and guard against malformed JSON (json_decode returns null for both "null" and invalid input — use JSON_THROW_ON_ERROR or check json_last_error()).

The exception listener does not catch everything. Symfony's security firewall short-circuits before your controller, so 401/403 will be rendered by the firewall entry point, often as HTML or a redirect. Configure a custom AuthenticationEntryPoint / AccessDeniedHandler that emits the same JSON envelope. Same story for OPTIONS preflight requests if you handle CORS at the web-server or listener level.

HttpException subclasses may bypass your listener. If you throw NotFoundHttpException, whether you get JSON or HTML depends on listener priority and kernel.debug. Register/inspect with bin/console debug:event-dispatcher kernel.exception and, if needed, decorate or re-prioritise. Keep your own exception types as the primary contract.

Circular references in serialization produce a 500 that looks like a listener bug. Fix with circular_reference_handler in framework.serializer config, and always specify groups on respond().

Debug the error path with APP_DEBUG=0. In dev, Symfony's error page can mask what the listener actually produces. Test the production shape before shipping.

Annotation → attribute migration. The 2021 release predates Symfony 6.2 attribute routing. If you're on 6.2+, your own controllers can use #[Route] regardless, but any annotation-driven config inside the bundle needs sensio/framework-extra-bundle compatibility checking.

Extension points are: (a) overriding the base controller, (b) decorating the exception listener with your own service that adds logging/request-id propagation and delegates, and (c) tagging your own normalizers. Prefer (b) over forking — it survives a vendor update if one ever comes.

Before adopting for a new project, compare against a maintained alternative (API Platform for full CRUD, or ~50 lines of your own kernel.exception listener + base controller). The bundle's value is the pattern, not the code; the pattern is easy to reproduce and easier to own.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core