NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Packagist · #3095 most downloaded on Packagist
Contracts and support classes for Laravel JSON:API packages.
Last release 6 months ago
28 Mar 2026
Ships fairly regularly
a new release about every 3 months
Nearly every release is documented
notes for 26 of 26 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
36 releases · first in 2021
One column per quarter.
Package now supports Laravel 13.
### Fixed - #27 Update UUID regex to be case-insensitive. This also means the regex now matches Laravel's UUID route parameter regex, which is where t
Improve exception message
Improve exception message
Package now supports both Laravel 11 and 12.
Add header to error source object.
Add header to error source object.
Fix meta bug in paginated relationship responses
Fix meta bug in paginated relationship responses
Remove more PHP 8.4 deprecation notices.
Remove more PHP 8.4 deprecation notices.
on authorizer contract.
on authorizer contract.
Authorizer contract now allows all methods
to return a bool or an Illuminate authorization response.More PHP 8.4 deprecation fixes.
More PHP 8.4 deprecation fixes.
Revert breaking changes released in minor version
Revert breaking changes released in minor version
Removed deprecation notices in PHP 8.4.
Authorizer contract now allows all methods to return a
bool or an authorizer response.Response classes now have a withoutHeaders() method to remove headers from the response.
withoutHeaders() method to remove headers from the response.withHeaders()
method on the JSON:API response classes. This was previously not merging headers, which was not correct and therefore
this is a bug fix. If you were relying on this behaviour, use the new withoutHeaders() method to remove any headers.### Fixed - #17 Fix incorrect self link in related resource responses, and remove related link that should not exist. This has been incorrect for some
self link in related resource responses, and
remove related link that should not exist. This has been incorrect for some time, but is definitely what
the spec defines here.Package is now licensed under the MIT License.
8.2.Can now create a JSON:API server once, without it being thread-cached. This is required for registering routes, as we do not expect that server instan
route:cache should have been used, so it would be inaccurate to leave the server thread-cached after
registering routes in a non-production environment e.g. test.### Added - #12 Add ulid() method to the matches ids trait. ### Fixed - #10 Use correct resolver for resource type.
### Added - #9 Can now cast a stdClass object to a Hash via the Hash::cast() method.
stdClass object to a Hash via
the Hash::cast() method.Upgrade to Laravel 10 and set minimum PHP version to 8.1.
8.1.### Added - #8 Allow relations to be conditionally eager loadable.
The JsonApiException now has a context() method. The Laravel exception handler uses this to obtain additional context information to log when logging
JsonApiException now has a context() method. The Laravel exception handler uses this to obtain additional
context information to log when logging the exception. This method returns the status code and the JSON:API errors so
that these can be seen if a JSON:API exception is logged.New Document\ResourceIdentifier::idIsEmpty() static method for checking that an id value is not empty. This check ensures that the trimmed string is e
Document\ResourceIdentifier::idIsEmpty() static method for checking that an id value is not empty. This check
ensures that the trimmed string is empty and that the string is not "0", as zero could be used for a resource id.
This new static method has been added to ensure the logic of determining if an id value is empty is in one place.Document\ResourceObject class now accepts an id of "0". Previously this was treated as empty, which is
incorrect.The LazyRelation class now has an all() method to get the related resources for a to-many relation as an array.
LazyRelation class now has an all() method to get the related resources for a to-many relation as an array.LazyRelation class now caches the to-one resource. Previously it only cached the to-many resources, so this
change makes the behaviour consistent.LazyRelation class would always throw an exception if iterated over. This has now been fixed.Added return types for internal methods, to remove deprecation warnings on PHP 8.1.
Support\AppResolver and Support\ContainerResolver - that lazily resolve the
current application and container instances. These have been added to enable support for Laravel Octane, which
recommends injecting a closure resolver for getting that current instances of the application or container. These
utility classes enable strictly type-hinted constructor dependency injection, as these classes are more specific about
what the resolver than just type-hinting the generic \Closure class which could return anything.Schema\Container class now takes an instance of Support\ContainerResolver as its first constructor
argument. This allows the schema container to lazily load the current container instance.Server\Server class now takes an instance of Support\AppResolver as its first constructor argument. In
addition, the $app property has been made private, and the deprecated $container property has been removed.
Child classes that need to access either the application or the container should use the new protected app()
method. This change allows the server instance to lazily load the current application instance.Server\ServerRepository class now only has a single constructor argument, which is an instance
of Support\AppResolver. The private $config property has also been removed. This change allows the server
repository to lazily load the current application instance.Added a JsonApiException test as this class requires breaking changes when upgrading Symfony to the next version.
JsonApiException test as this class requires breaking changes when upgrading Symfony to the next version.Relationship response classes now merge relationship links with the links set on the response classes. This can be disabled by calling the withoutRela
withoutRelationshipLinks() method on these classes.ConditionalField class now has a value() method to get the value of the field without checking whether the
field is meant to be skipped.ConditionalFields class now has a public values() method to get the values of the fields without checking
whether the fields are meant to be skipped.JsonApiResource class now has a
protected serializeRelation() method, that allows a developer to customise the serialization of a JSON:API
resource's relationship beyond the default implemented by this package.Relation class now has two additional helper methods: onlySelfLink() and onlyRelatedLink().Links object:
ArrayAccess.has() method for checking whether a key exists in the links object.hasSelf() and getSelf() methods for accessing the self link defined by the JSON:API spec.hasRelated() and getRelated() methods for accessing the related link defined by the JSON:API spec.all() method for getting the links as an array.JsonApiResource::relationship() method
now safely iterates over relationships even if they are conditional. This means the named relationship will always be
found even if it is marked to be skipped when serializing the resource. This is implemented through a
new RelationIterator class.Ensure the DataResponse class passes on its created flag if its data member is already a JsonApiResource.
DataResponse class passes on its created flag if its data member is already a JsonApiResource.Location header to a response if the resource has a self URL. Previously the header would be set with
a null value.The JsonApiException class now has is4xx() and is5xx() helper methods for determining whether the HTTP status code is in the 4xx or 5xx range.
showRelated method to
authorize the show-related controller action. Previously the showRelationship method was used to authorize both the
show-related and show-relationship controller actions. This change means that authorizers can implement different
authorization logic if needed. However, our default authorizer (the Auth\Authorizer class) remains unchanged in that
both actions expect there to be a view<RelationshipName> method on the policy to authorize these actions.JsonApiException class now has is4xx() and is5xx() helper methods for determining whether the HTTP status
code is in the 4xx or 5xx range.Schema\Schema class no longer sorts fields by their name. This means fields are now processed in the order that
they are defined by the developer. Fields can be listed in alphabetical order by the developer if that is the desired
order.Auth\Authorizer class is no longer final and can now be extended if needed.JsonApiService class.BREAKING Removed the iterable type-hint from the Contracts\Pagination\Page::withQuery() method. The value passed can be any value that can be cast to
Contracts\Pagination\Page::withQuery() method. The value passed
can be any value that can be cast to a Core\Query\QueryParameters object. This change also affects the
Core\Pagination\AbstactPage::withQuery() method, that has been updated to remove the type-hint. This will affect any
child classes that have overloaded this method.Core\Resources\ResourceCollection::withQuery() method. The value
passed can be any value that can be cast to a Core\Query\QueryParameters object.links() method when passing links to the encoder. This
fixes a bug whereby pagination links were not added to the compound document for related resources and relationship
identifier responses.collect() method was being used, which meant QueryParameters::toArray() would be used to serialize query
parameters. This has now been updated to use QueryParameters::toQuery() instead, which is the correct method to use.Include paths and sparse field sets that should be used when encoding JSON:API responses can now be manually set on response classes using the withInc
withIncludePaths() and withSparseFieldSets() methods, or using the convenience
withQueryParameters() method to set both from a query parameters object. When include paths and/or sparse field sets
are set on the response, these are used when encoding the response JSON instead of determining these query parameters
from the request. If no include paths or sparse field sets are set on the response, the previous behaviour of
determining these from the request is used.Responses\Concerns\IsResponsable trait to a new Responses\Concerns\HasEncodingParameters trait. As part of this
change, the previous protected method fieldSets() has been renamed sparseFieldSets().Attribute and ID interfaces no longer implement Sortable and instead have a isSortable() method
directly defined on their interface.Sortable interface is now intended to be implemented on a class that is an additional sort field to those
that are attributes. It has one method: sortField() which returns the name of the sort field.Schema::isSortable() method has been renamed isSortField(). This makes it clearer that the method is
querying whether the provided name is a valid sort field.Schema::sortable() method has been renamed sortFields(). This makes it clearer that the method is
returning a list of the sort field names.sortField() and sortables() methods to the Schema interface.The Core\Server\Server::$container property is deprecated and will be removed in 1.0.0-stable. Child classes should use the new Server::$app property…
Contracts\Resources\Factory interface now has a canCreate() method to determine whether the factory can create
a JSON:API resource for the supplied model.Contracts\Schema\Container interface now has a existsForModel() method, to determine whether a schema exists
for the supplied model class.Core\Resources\Container class now expects a single factory instance to its constructor. This was changed as
there was no requirement for multiple resource factories to be loaded into the container. The container still supports
injecting a factory, as this allows the creation of resources by the container to be customised, without having to
re-implement the logic within the container class. As part of this change, the Container::attach() method was also
removed.Core\Resources\Factory class constructor was amended to only expect a schema container. Additionally the method
signature of the protected build() method was changed to receive a schema instance and the model being converted to
a JSON:API resource.Core\Server\Server and Core\Server\ServerRepository classes are now injected with the Laravel application
instance, instead of just type-hinting the container. This change was made to allow code within servers to access the
application environment, using $this->app->environment() rather than having to use app()->environment()
(which used to be the case as the injection was only type-hinted as the container contract).Server class now correctly passes extra parameters in its url() method. Previously these were passed to
Laravel's url() helper - but that helper only appends extra parameters if there is no HTTP host in the provided
path. The server's url() method now passes these as we always went them appended, regardless of whether the API's
base path has a HTTP host or not.Core\Server\Server::$container property is deprecated and will be removed in 1.0.0-stable. Child classes
should use the new Server::$app property instead.Contracts\Resources\Factory::handles() method has been removed in favour of using the new canCreate() method
instead.Contracts\Schema\Container::resources() method has been removed, in favour of resource factories using the
schema container's existsForModel() and schemaForModel() methods.BREAKING Added the following methods to the Contracts\Schema\Schema interface: isFilter(), isSparseField, isSortable() and hasSelfLink(). These method
Contracts\Schema\Schema interface: isFilter(),
isSparseField, isSortable() and hasSelfLink(). These methods have been added to the abstract schema class
provided by this package, so this is unlikely to have a significant impact on implementing packages.Contracts\Query\QueryParameters interface:
unrecognisedParameters method. This returns any query parameters that are not defined by the JSON:API
specification, which allows implementations to add support for additional query parameters as needed.filters method now returns a FilterParameters object or null. Previously it returned an array or null.$baseUri argument on the Contracts\Resources\Serializer\Relation interface is now nullable.Contracts\Store\Store interface now has a findOrFail method. This is unlikely to be breaking in
most implementations because the Core\Store\Store class will be in use and has been updated.cast method to the Contracts\Resources\Container interface. This is unlikely to be breaking
in most implementations because the Core\Resources\Container class will be in use and has been updated.Contracts\Schema\IdEncoder interface to encode model IDs to JSON:API resource IDs.FilterParameters class for handling a collection of filter parameters received from a client.FieldSets, IncludePaths and SortFields classes all now have a collect() method, that returns a collection
object.IncludePaths and SortFields classes now have filter, reject and forSchema methods.SortField class now has static ascending and descending methods, to easily create a sort field with the
specified direction.QueryParameters class now has a toQuery() method, that casts the value back to a HTTP query parameter array.
This is different from QueryParameters::toArray(), as the include and sort parameters are strings in a HTTP
query array.QueryParameters class now has a forSchema() method, that returns a new query parameters instance that contains
only parameters valid for the supplied schema.Document\ResourceObject class has a new withRelationshipMeta method for adding meta for a specified
relationship./api/posts/1/comments
endpoint. Previously the DataResponse class was used for this endpoint, but the new classes allow for relationship
meta to be merged into the top-level meta member of the response for the endpoint.HasPageMeta and HasPageNumbers, so that these can be used in both the
Eloquent and non-Eloquent implementations.dump method to the Core\Document\ResourceObject class.Contracts\Schema\Schema::repository() is now nullable.Contracts\Store\Store::resources() is now nullable.QueryAllBuilder contract has been removed; support for singular filters is now implemented via the
HasSingularFilters interface which is intended to be added to classes implementing QueryManyBuilder. As part
of this change, the QueriesAll::queryAll() method now has the QueryManyBuilder interface as its return type.QueryManyBuilder contract no longer has pagination methods on it. If a builder supports pagination, it must
add the HasPagination interface.cursor method from the QueryManyBuilder contract, as it is not required on the contract
(implementing classes can add it if needed). The get method now has a return type of iterable instead of the
Laravel Collection class.Contracts\Encoder\Encoder interface now has two methods for encoding resource identifiers:
withToOne and withToMany. These replace the withIdentifiers method, which has been removed.Core\Responses namespace to the Core\Responses\Internal namespace. This is
considered non-breaking because the classes are not part of the public API (responses that can be used for the public
API are still in the Core\Responses namespace):
PaginatedResourceResponseResourceCollectionResponseResourceIdentifierCollectionResponseResourceIdentifierResponseResourceResponseCore\Responses\Concerns\EncodesIdentifiers trait. This is considered non-breaking as the trait was only
intended for internal use.QueryParameters::setFieldSet() method now correctly passes the fields lists as an array to the field set
constructor.Core\Document\ResourceObject::merge() method handling of merging relationships. Previously this used
array_replace_recursive to megre the relationship object, but this led to incorrect merging of data members,
particularly for to-many relationships. This has been altered to array_replace, so that the data, links and
meta members of the relationship are replaced with the values from the resource object's relationship that is being
merged in.If closures are used for data and/or meta on the Resources\Relation class, the closures will now receive the model as their first and only argument.
Resources\Relation class, the closures will now receive the model
as their first and only argument.Resources\Relation class is now returned by a protected value method, allowing child
classes to modify the default behaviour if needed.Creatable interface, which the JsonApiResource class delegates to when determining whether a resource was
created within the current HTTP request.$container property on the Server class is now protected and can be used by child classes if needed.$resource property on the Resources\Relation class is now protected.Server\Server contract no longer has a serving() method on it. This has been removed from the contract so that
developers can type-hint dependencies in their serving method.BREAKING The builder interfaces in the Contracts\Store namespace now have a withRequest method. This allows passing the request into the builder proce
Contracts\Store namespace now have a withRequest method. This allows
passing the request into the builder process as context for the action.Contracts\Routing\Route contract now has an authorizer method, for getting the authorizer
instance for the route.Contracts\Schema\Schema contract now has a url method, for generating a URL for the resource that
the schema defines.allInverse() method to the Contracts\Schema\Relation contract. This returns a list of the
allowed resource types for the relationship. Typically this will just be one resource type; polymorphic relations will
return multiple.get method on the ConditionalField class for retrieving the value of the field.withServer method, for explicitly setting the JSON:API server to use when generating the
response. This is useful when returning responses from routes that do not have the JSON:API middleware applied to
them.MetaResponse class for returning a JSON:API response with a document containing a top-level meta value.DataResponse class now has a didntCreate method for ensure the resource response does not have a 201 Created
status.Contracts\Auth\Authorizer contract now requires the model class to be passed as the second argument
on the index and store methods. Also, all methods have been updated to type-hint the Illuminate request object.using method has been renamed to withQuery on the following interfaces in the Contracts\Store
namespace:
QueryManyBuilderQueryOneBuilderResourceBuilderToManyBuilderToOneBuilderContracts\Resources\Serializer\Hideable contract has been updated to type-hint the request class in
its method signatures.Core\Schema\SchemaAware trait has been moved to the Core\Schema\Concerns namespace, for
consistency with other traits.Core\Schema\Container class now expects the server instance to be passed as its second constructor
argument, with the list of schemas now its third constructor argument.Core\Schema\Schema class has been changed to the server
instance that the schema belongs to. This change was made so that schemas can generate URLs using the server instance,
while also injecting the server's schema container into fields if needed.fields query parameter to the Core\Query\FieldSets and Core\Query\FieldSet classes.Removed the deprecated create() method, as this was never intended to be brought in from the old package.
Contracts\Schema\Relation contract now has a isValidated() method, to determine if the relation
value should be merged when validating update requests. There is now a Core\Schema\Concerns\RequiredForValidation
trait that can be used on relationship fields to implement the required method.Core\Documents\ResourceObject class:
merge() method for merging two resource objects together. This is useful for update validation, where the
values supplied by a client need to be merged over the existing resource field values.putRelation and replace methods now accept an instance of UrlRoutable for the id value of to-one or
to-many relations.$schemas property. This has
been added so that a schema class can be instantiated directly from the service container if the schema container is
bound in the service container.Core\Resources\ConditionalList class, for iterating over conditional attributes but yielding them as a
zero-indexed array list.Core\Document\ResourceObject::withoutLinks() method now correctly removes both resource links and relationship
links.Core\Resources\Concerns\ConditionallyLoadsAttributes trait is now ConditionallyLoadsFields.Core\Resources\ConditionalAttr is now ConditionalField.Core\Resources\ConditionalAttrs is now ConditionalFields.Contracts\Server\Server interface ($parameters) has been made optional.mustValidate() and isValidated() methods from the Core\Resources\Relation class. These
fields are now defined on the schema's relation field instead of the resource's relation.Core\Documents\ResourceObject class:
create() method, as this was never intended to be brought in from the old package.Arrayable contract (and therefore the toArray() method). This is because toArray() was always
ambiguous - would it return the field values, or the JSON representation of the resource? Replace toArray()
with jsonSerialize(). The all() method continues to return the field values.BREAKING The Contracts\Encoder\Encoder contract now has a withRequest method to inject the current HTTP request into the encoding process. The respons
Core\Resources\JsonApiResource is no longer abstract, and now expects the schema and the model to
be injected via its constructor. It will use the schema to convert a model to a JSON:API resource. This allows the
resource classes to be optional, as the resource resolution logic can now fall-back to the JsonApiResource when no
specific resource class exists. Schema fields must implement the Contracts\Resources\Serializer\Attribute
and Contracts\Resources\Serializer\Relation interfaces on their fields for the serialization to work.Contracts\Encoder\Encoder contract now has a withRequest method to inject the current HTTP
request into the encoding process. The response classes have been updated to pass the request through to the encoder
in their toResponse() methods.Contracts\Schema\Container contract now has a schemaForModel method to lookup a schema by
providing either a model instance, or the fully-qualified class name of a model.Contracts\Schema\ID contract now has a key() method, that can return the model key for the ID.Contracts\Schema\Schema contract now has new methods:
uriType() which returns the resource type as it appears in URIs.idKeyName() which returns the object key for the id value.Contracts\Resources\JsonApiRelation contract for the relation object returned by the
JsonApiResource::relationships() method. This has the methods on it that encoders can rely on when encoding the
relationship to JSON.Contracts\Schema\Relation contract now has a uriName() method for retrieving the relationship's
field name as it appears in a URI. The JsonApiResource
class now automatically injects this value from the schema field into the resource relation object.Core\Resources\ConditionalIterator class for iterating over values that could contain conditional attributes.attributes, relationships, meta and links method of the JsonApiResource
class now require the request to be passed as a parameter. This is to bring the resource in line with Laravel's
Eloquent resource, though our implementation allows the request to be null to cater for resource encoding outside of
HTTP requests (e.g. queued broadcasting). Additionally, the relationship method return type has been changed to the
new Contracts\Resources\JsonApiResource
contract.exists and create methods on the Contracts\Resources\Container contract now correctly type-hint
the parameter as an object.createResource method on the Contracts\Resources\Factory contract now correctly type-hints the
parameter as an object.Core\Resources\Factory class now expects a schema container and an optional
array of resource bindings (instead of an iterable). If a null value is provided for the bindings, the bindings will
be retrieved from the schema container. Additionally, the protected
build method signature has been updated to correctly type-hint the second argument as an object.Core\Resources\Relation class have been changed so that it now
receives the model and base URI - rather than the JsonApiResource object. This change was made so that it can be
used more broadly.attach and attachAll methods of the Core\Resources\Factory class have been removed, because
they were not in use.Initial release.
Initial release.
Your coding agent can read these notes before it upgrades. Set up the MCP server →