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

dunglas/api-bundle

API Platform Core is a powerful Symfony bundle for building hypermedia-driven REST and GraphQL APIs. It supports JSON-LD, Hydra, OpenAPI, JSON:API, HAL and Problem Details, letting you create fully featured, high-performance API-first projects in minutes.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal setup

  1. Install the Laravel bridge:

    composer require api-platform/laravel
    

    Publish its config so you can tweak defaults:

    php artisan vendor:publish --tag=api-platform
    

    Routes under the /api prefix (docs included) are registered automatically — no provider entry in config/app.php is needed in Laravel.

  2. Declare your first resource on an Eloquent model:

    use ApiPlatform\Metadata\ApiResource;
    use ApiPlatform\Metadata\Get;
    use ApiPlatform\Metadata\GetCollection;
    use ApiPlatform\Metadata\Post;
    
    #[ApiResource(
        operations: [new Get(), new GetCollection(), new Post()],
        normalizationContext: ['groups' => ['post:read']],
        denormalizationContext: ['groups' => ['post:write']],
    )]
    class Post extends Model {}
    
  3. First use case: hit /api/posts for the collection (Hydra/JSON:API depending on format), /api/posts/1 for an item, and /api/docs for the interaction-less OpenAPI UI. Confirm routes with php artisan route:list --path=api.

Where to look first

  • config/api-platform.php — formats, docs, defaults, cache wiring.
  • The model itself — operations, groups, filters all live as attributes.
  • /api/docs — the generated OpenAPI is the fastest way to verify what an attribute actually produced.
  • composer show api-platform/laravel — 5.0.4 is a patch on top of 5.0.3 with a large batch of metadata/JSON Schema fixes; check the version before debugging schema oddities.

Implementation Patterns

Resource design

  • Keep #[ApiResource] on the model and put per-operation tuning on the operation object (new Get(security: "..."), new GetCollection(paginationEnabled: false)).
  • Prefer normalizationContext/denormalizationContext with #[Groups] on properties over hand-written resources; sparse fieldsets and JSON:API fields[] then work for free.
  • Use DTOs (#[ApiResource] on a plain class) when the API shape diverges from the table — v5 handles resources without an attribute on the backing class for shortName resolution, so uriTemplate/shortName stay predictable.
  • Operation objects are immutable for the newer with* helpers: Put::withAllowCreate(), Link::withFromProperty() now return a new instance (5.0.4). Always assign the return value; chained calls that relied on mutation silently lose the setting.

Filtering and pagination

use ApiPlatform\Laravel\Eloquent\Filter\SearchFilter;
use ApiPlatform\Laravel\Eloquent\Filter\OrFilter;
use ApiPlatform\Metadata\ApiFilter;

#[ApiFilter(SearchFilter::class, properties: ['title' => 'partial', 'status' => 'exact'])]
#[ApiFilter(OrFilter::class, properties: ['id', 'slug'])]
class Post extends Model {}
  • Array query parameters are documented in OpenAPI with bracket notation (?id[]=1&id[]=2); OrFilter also accepts a single scalar (?id=1), so hand-written clients don't need to always send arrays.
  • OrFilter now handles nested properties via a left join (fixed in 5.0.4 on the Doctrine side; the generator/parameter pipeline is shared) — properties: ['author.email'] style mappings behave like a top-level property instead of erroring or dropping the condition.
  • Empty vs. absent params matter again: an empty scalar query param (?status=) now returns 422 (behaviour restored in 5.0.4). If you were relying on empty strings being coerced to null/ignored, strip them client-side or map them explicitly in a custom filter.
  • Disable pagination per operation with new GetCollection(paginationEnabled: false) — but see the security gotcha below.
  • SortDirection enums are accepted in ordering configuration (5.0.4) — passing the enum instead of the string no longer raises a TypeError.

Security

  • Put security on the operation, not the class, when read and write rules differ: new Get(security: "is_granted('ROLE_USER')").
  • Collection authorization is evaluated against the resource class (not per item) for non-paginated collections since 5.0.2 — safe to rely on for "all-or-nothing" collection access.

State providers / processors

  • Custom read logic: implement a state provider and reference it with provider: on the operation; keep it thin and let Eloquent do the heavy lifting.
  • Custom write logic (derived fields, audit columns): use a processor (processor:) rather than model events, so the behaviour is scoped to the API operation.
  • A parameter-level provider: is no longer clobbered by the filter provider (5.0.4) — you can attach both a custom #[Parameter] provider and an #[ApiFilter] to the same property without one winning arbitrarily. Verify the resolved provider via a dd() in the provider if you used this combination before.
  • Parameter declarations got two ergonomic upgrades in 5.0.4: #[Parameter(operations: [...])] accepts operation class names (operations: [Get::class, GetCollection::class]) as well as instances, and operation-level parameters now take precedence over #[Parameter] attributes declared on the property class.
  • If you catch PartialDenormalizationException in a custom provider, note that 5.0.4 stopped calling the deprecated getErrors() internally; read the constraint violations directly rather than relying on that accessor.

Relations and links

  • Optional belongsTo relations now accept null on write (5.0.4, Laravel-specific). Before, a nullable FK sent as null could fail denormalization; if you had a custom setter or prepareForValidation shim for that, remove it and let the relation handle it.
  • Explicit readableLink/writableLink survive on collections of non-resource classes (5.0.4) — useful when a collection returns value objects rather than entities.
  • The rest of the 5.0.4 link work is Doctrine-only (arbitrary joins emit ON, put-create under a slug parent link, links accepting resolved resources). Don't go looking for those PRs when Eloquent links misbehave — the Laravel bridge has its own relation-based link handler.

Validation

  • Reuse Laravel validation via API Platform's validator integration plus standard constraints; group-scoped validation is reflected in JSON Schema names (...-validation_groups-...), so generated schemas are distinguishable per group.
  • GroupSequence is supported as of 5.0.4 — use it when validation must short-circuit (e.g. "don't check uniqueness until the format is valid") instead of chaining constraints by hand.
  • Backed enum violations now return 422 rather than bubbling up a 500/400 (5.0.4). If clients special-cased enum errors, simplify them.
  • Add validationContext: ['groups' => ['post:patch']] on properties that must not be required on PATCH.
  • If you ever hit a mismatch between a property-level #[Parameter] and an operation-level one, the operation wins (5.0.4) — don't debug the property attribute expecting it to apply.

HTTP caching

  • Tag-based invalidation is wired on Laravel as of 5.0.2, and purging a write clears every collection operation of the resource (not just one). If you front the API with a cache proxy, verify the tags processor is present in the container after upgrading.

GraphQL / OpenAPI

  • GraphQL: custom query arguments resolve after the resource loop — argument order between multiple custom queries is no longer silently swapped. stateOptions and map are now forwarded to the QueryCollection parent constructor (5.0.4), so subclassed/extended collection queries keep their state configuration.
  • GraphQL parameters can now be declared in parameter attributes on properties (5.0.4). Previously the "operation not declared in #[ApiResource(operations: [...])]" guard threw for GraphQL ops too; that guard now correctly applies only to undeclared HTTP operations.
  • OpenAPI/JSON Schema fixes you can rely on after 5.0.4: mixed emits an empty schema, intersection types emit allOf, nested resources honour output DTOs, nested gen_id follows the property name, and operation groups survive into the schema context. Regenerate any client code — the diff will be non-trivial but correct.

Gotchas and Tips

Caching and metadata

  • Metadata is cached. After changing attributes, run php artisan config:clear && php artisan cache:clear. In dev, point the metadata pool at the array store.
  • 5.0.2 fixes caching metadata read from a missing table — previously a resource whose migration hadn't run could be cached as "no metadata" and stay broken until a manual cache flush. If you hit that on an older patch, flush once after upgrading.
  • Several 5.0.4 metadata fixes only re-apply cleanly on a cold cache (queryParameterValidationEnabled now persists on ApiResource, contentNegotiation is copied by withOperation(), defaults that use can* getters, explicit readableLink/writableLink on non-resource collections). If a setting "doesn't take", clear the cache before opening an issue.

Filter quirks

  • The Laravel filter generator previously emitted a duplicated use statement for the filter interface — if you generated a custom filter before 5.0.2, open the file and de-duplicate the import (a fatal "cannot use ... as ... because the name is already in use" otherwise).
  • Prefer explicit properties maps with strategies (exact, partial, start, end) — implicit behaviour differs per filter and shows up as confusing SQL.
  • LIKE escaping is now portable across databases (5.0.4); if you had hand-rolled addcslashes in a custom filter, drop it — it will now be double-escaped.

Security pitfalls

  • Non-paginated collections used to authorize per item; if you worked around this with a custom provider or a security expression on the first item, you can drop it.
  • security on GetCollection does not filter rows — pair it with an extension/query scope for per-tenant visibility.

Serialization

  • JSON:API sparse fieldsets apply to included resources too, so fields[comments] finally trims sideloaded data. Expect payload-size changes if clients relied on full included objects.
  • Groups on non-resource classes produce correct JSON Schema; useful when your resource embeds value objects.
  • Declaring a parameter attribute on a property whose HTTP operation isn't in #[ApiResource(operations: [...])] throws instead of being ignored — a good thing, but it surfaces as a hard error on upgrade. GraphQL operations are exempt as of 5.0.4.

Testing

  • The bridge's own suite moved to ApiPlatform\Test\ApiTestCase and createOne() for for() relations (5.0.4, PHPUnit 13 compatibility). If you copied test scaffolding from older package examples, update the base test case import — the old path breaks under PHPUnit 13.

Debugging

  • php artisan route:list for the routing picture; /api/docs for the metadata picture; var_dump of the operation objects via a dd() in a state provider for the runtime picture.
  • Filter debugging: log the resolved query parameters; if a filter silently ignores a param, the properties key doesn't match the attribute name.
  • OpenAPI mismatches are almost always stale metadata cache, not a bug — especially after 5.0.4, which changed a lot of schema output. Diff a regenerated spec instead of eyeballing it.
  • If you run under Octane or another long-lived worker, the skolem IRI converter and Mercure publisher are now reset between requests (5.0.4) — but any custom singleton provider holding per-request state is still your responsibility.

Upgrade notes (5.0.3 → 5.0.4)

Patch release, no breaking changes or deprecations. Worth bumping for the Laravel-relevant fixes: nullable optional belongsTo writes, restored 422 on empty scalar params, 422 for backed enum errors, GroupSequence support, OrFilter nested properties, operation class names in #[Parameter(operations:)], operation-over-property parameter precedence, and a large batch of JSON Schema/OpenAPI correctness fixes. Behavioural changes to watch: empty scalar params return 422 again, schema output shifts for mixed/intersections/nested resources, and operation-level parameters now beat property-level ones. Doctrine-only fixes in this release (portable LIKE escape, ON joins for arbitrary links, put-create under a slug parent, resolved resources in links, ORM 3 column defaults) are listed here for completeness but won't change Eloquent behaviour. Clear config + cache after upgrading and regenerate any OpenAPI-derived clients.

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.
djstarcom/laravel-breadcrumbs
djstarcom/laravel-server-timing
class-atlas/laravel-flitt
ipregistry/ipregistry-laravel
daimakuai-ext/config
tomassalazarlopez/laravel-filemanager
ergare17/tasks
magentron/elasticemail-php
anilcancakir/laravel-agent-mcp
callcocam/laravel-whatsapp-cloud
winavin/permissions
daimakuai-ext/reporter
springjk/laravel-admin
kwaadpepper/laravel-storage-manager
karlerss/laravel-db-script-manager
hexincorp/laravel-debugbar
quellabs/canvas
quellabs/annotation-reader
mydnic/volet-feature-board
wmde/fundraising-phpcs