NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Packagist · #3139 most downloaded on Packagist
Serialize Eloquent models as JSON:API resources.
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 20 of 20 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
31 releases · first in 2021
One column per quarter.
Package now supports Laravel 13.
laravel-json-api/core v4.New asInteger() method on deserializes value trait
New asInteger() method on deserializes value trait
asInteger() method added to the DeserializesValue
trait.Package now supports Laravel 11 and 12.
Remove deprecation notices in PHP 8.4.
laravel-json-api/core v4 and v5.Fix cursor parser not handling id not existing
Fix cursor parser not handling id not existing
Add where-any and where-all filters
Add where-any and where-all filters
WhereAll and WhereAny filters.car and carOwner would result in just carOwner.### Added - #37 Add Eloquent cursor pagination implementation.
Support Eloquent dynamic relationships
Support Eloquent dynamic relationships
Package is now licensed under the MIT license.
8.2.assert() within fillable relation field classes rather as an optimisation.self as return type on Eloquent query
classes. This is potentially breaking any of these classes have been extended.Allow any Eloquent relation class in relation queries.
Allow any Eloquent relation class in relation queries.
QueryToMany and QueryToOne classes. This means packages
like culturegr/custom-relation will work with this package.### Fixed - #29 Avoid unnecessary query when there is no need to count a relationship.
Upgraded to Laravel 10 and set minimum PHP version to 8.1.
8.1.New MultiPaginator that allows a schema to offer multiple different pagination strategies.
MultiPaginator that allows a schema to offer multiple different pagination strategies.laravel#223 Ensure a model always has fresh data from the database after a write operation, to prevent stale data on cached relationships.
### Added - #27 Added the WhereNull and WhereNotNull filters.
WhereNull and WhereNotNull filters.Pass sparse field sets to the JsonApiBuilder class, ensuring that they are present on any generated page objects. Previously this omission meant that
JsonApiBuilder class, ensuring that they are present on any generated page objects.
Previously this omission meant that page URLs were missing any fields sent by the client.The Number field can now be configured to accept numeric strings by calling the acceptStrings() method on the field.
Number field can now be configured to accept numeric strings by calling the acceptStrings() method on the
field.JsonApiBuilder class was previously converting a null decoded id to an empty string when querting for a
resource id. This has been fixed to pass null to the query builder instead of the empty string, as this was most
likely the cause of failures in Postgres.Added return types for internal methods, to remove deprecation warnings on PHP 8.1.
ReadOnly contract and trait. This is because PHP 8.1 introduced readonly as a reserved word. The following changes
were made:
LaravelJsonApi\Eloquent\Contracts\ReadOnly is now IsReadOnly.LaravelJsonApi\Eloquent\Fields\Concerns\ReadOnly is now IsReadOnly.The maximum PHP version is now 8.0. This is because this package does not work in its current form with PHP 8.1. The next major version of this packag
WhereHas and WhereDoesntHave filters
that have been broken since 1.0.0. Previously they have been iterating over filters on the schema to which the
relationship belongs - which is incorrect. They now correctly iterate over the filters on the schema on the other side
of the relationship (this inverse filter).This change has been made as the countable feature is not considered production ready as we plan to make breaking changes to the implementation. By ch…
HasWhereHasWhereDoesntHaveHasColumn and
HasOperator traits.FilterApplicator and SortApplicator.SoftDeleteDriver to use class_uses_recursive to check if the model support soft-deleting.Scope::make() method to use static instead
of self.QueryBuilder namespace. This change should not affect consuming applications as these
classes are meant for internal package use:
JsonApiBuilder class.ModelLoader class.Aggregates namespace.EagerLoading namespace.null value in the filter HasDelimiter trait.LaravelJsonApi\Eloquent\Pagination\CursorPagination
to LaravelJsonApi\CursorPagination\CursorPagination.Developers can now fully control the extraction of attribute values from a model by providing a closure to the extractUsing() method on attributes. Th
extractUsing() method on attributes. This callback receives the model, the column name, and the serialized value.
Resource classes are still the recommended way of fully customising serialization of models to JSON:API resource
objects. However, the extractUsing() method is useful where a developer only needs to customise one or two attribute
values on a resource.Updated the Pagination\ProxyPage::withQuery() method to remove iterable type-hint that has been removed from the page interface. The class was also ma
Pagination\ProxyPage::withQuery() method to remove iterable type-hint that has been removed from the
page interface. The class was also made final, as it is not intended to be extended. Although these changes are
technically breaking, they are unlikely to affect consuming applications.JsonApiBuilder was incorrectly casting null to an include paths object. On pages, this would incorrectly
result in pagination links having an include= (empty) parameter. This has been fixed, so include paths will only be
set on the pagination links if include paths were actually specified.Schemas now support additional sort field classes, that define how to sort models using sort fields that are not attributes. Sort field classes must i
SortField contract. Three initial sort classes are available:
SortColumn, SortCountable and SortWithCount.$defaultSort property.The HasOne field can now handle detaching a related model from the relationship in three ways. Either it will set the inverse relationship columns to
HasMany field can now handle detaching models from
the relationship in three ways. Either it will set the inverse relationship to null (the default behaviour), or it
can delete the related models using either the Model::delete() or Model::forceDelete() methods. The default
behaviour matches the behaviour in previous versions, so this change is non-breaking. The behaviour can be configured
via the keepDetachedModels(), deleteDetachedModels() and forceDeleteDetachedModels() methods.HasOne field can now handle detaching a related model from the relationship in three ways. Either it will set
the inverse relationship columns to null (the default behaviour), or it can delete the related model using either
Model::delete() or Model::forceDelete(). The default behaviour matches the behaviour in previous versions, so this
change is non-breaking. The behaviour can be configured via the keepDetachedModel(), deleteDetachedModel() and
forceDeleteDetachedModel() methods.When using the Attribute::fillUsing() method to customise filling an attribute value into a model, the closure now receives the entire validated data
Attribute::fillUsing() method to customise filling an attribute value into a model, the closure now
receives the entire validated data as its fourth argument. This allows the closure to use other attributes when
calculating the value to fill into the model.belongsTo, hasOne,
hasOneThrough and morphOne relations that can have default related models. As part of this feature, the model
hydrator will now iterate through loaded relations on the model and save any models that are dirty.Contracts\Fillable::fill() method now expects the entire validated data as its third argument.Contracts\Fillable interface now has a mustExist() method. This allows an attribute to indicate
that the primary model being filled must exist in the database before the attribute is filled. This is intended for
use by attributes that fill related models.Contracts\FillableToOne and FillableToMany interfaces now no longer extend the Fillable
interface. This is so that the fill() methods can correctly type-hint the related identifier(s) that are expected
when filling a relationship. Effectively the Fillable contract is now intended for use by the id field and
attribute fields.*To-many* relationships are now countable. This allows a client to specify, via a query parameter, which relationships it wants to be counted. These a
meta member. Refer to documentation for implementation details.WhereIdInWhereIdNotInEagerLoading namespace are now marked as
internal, as they are not intended for use outside of this package. The public API is JsonApiBuilder::with(),
ModelLoader::load() and ModelLoader::loadMissing().loader() method to loaderFor($modelOrModels).JsonApiBuilder class now expects the schema container as its first argument. To construct a new JsonApiBuilder
instance, the Schema::newQuery() and Relation::newQuery() methods should be used.Pagination\Concerns\HasPageMeta trait as the trait is now in the laravel-json-api/core
package as LaravelJsonApi\Core\Pagination\Concerns\HasPageMeta.Generally this should not cause any breaking changes, because the eager loading classes were effectively used internally to handle eager loading. Chan…
SoftDeletes trait from this package and add a Fields\SoftDelete field to their list of
fields. Refer to documentation for full list of capabilities.WithTrashed and OnlyTrashed filter classes.MorphToMany JSON:API relation field. This
wraps several sub-relation fields and presents them as a single polymorphic relationship. The relationship value works
both as the data member of the relationship object and as a relationship end-point. The relationship is modifiable
when every sub-relation is writeable (implements the FillableToMany relation) and each resource type that can be in
the relationship maps to a single sub-relation. Include paths also work, with the include paths only being applied to
the sub-relations for which they are valid.Model::delete instead of Model::forceDelete. This change was required when
adding full support for soft-deleting resources.sync, attach and detach methods on the FillableToMany interface now type-hint iterable as
their return type. Previously they type-hinted the Eloquent collection class.skipMissingFields methods (that existed in multiple
locations) and rewriting the EagerLoadPath class.Schema class. These were originally added as convenience methods
if writing custom controller actions - however, their use is now not suitable as all database querying should be
executed via the repository class to ensure Eloquent query builders are created according to the database driver that
is in use. The methods are:
Schema::newQuery()Schema::query()The Relation::inverseType() method is deprecated and will be removed in 1.0-stable. Use Relation::type() instead.
indexQuery and relatableQuery methods. These allow filtering for authorization
purposes when a list of resources is being retrieved. For instance, it could filter those queries so that only models
belonging to the authenticated user are returned.Schema::isSingular() method.withRequest() method and renames using() to withQuery().Fillable contract now type-hints the
request class in its read-only method signatures, and allows it to be null. The ReadOnly trait has been updated,
so this is unlikely to affect field classes if the trait has been used.ModelHydrator class via its new withRequest() method, it is
now assumed the hydration is occurring outside of a HTTP request. I.e. that the developer is manually triggering the
hydration. Without the HTTP request, fields will not be checked for their read-only state and will be filled if the
provided data has a value for the field. Implementing libraries must ensure that withRequest() is called when
filling values provided by a HTTP client.Builder class to JsonApiBuilder. This change was made as it was confusing what
a Builder referred to, because Laravel uses this class name for Eloquent builders.Relation::type() method should now be used to set the inverse resource type on a relationship field.Builder::filters() method now correctly yields both the schema's filter and the filters from a relationship, if
one is set. Previously the filters were not yielded correctly if there was a relationship.QueryToOne and QueryToMany builders now correctly use the model's relation name instead of the JSON:API field
name when retrieving the relationship object from the model. Previously this would have failed with an error if the
model relationship name was not the same as the JSON:API field name.Relation::inverseType() method is deprecated and will be removed in 1.0-stable. Use Relation::type()
instead.Relationship fields now implement the new isValidated() method, indicating whether the field value should be merged with client provided values for an
isValidated() method, indicating whether the field value should be merged
with client provided values for an update request. By default, the BelongsTo and MorphTo relations are
validated, whereas all other fields are not. This is a sensible default, as the BelongsTo/MorphTo identifiers are
stored on the model so are likely to be required for validation. The defaults can be overidden on the fields using
the mustValidate() or notValidated() methods.$with property on the
schema, which is returned by the public with() method.EagerLoader, EagerLoadMorphs and EagerLoadPath to the EagerLoading namespace.BelongsToMany field now correctly yields both its own filters and filters from its pivot fields. Previously the
filters were not yielded correctly if both the field and pivot had filters.BREAKING Split the Arr field class into two: ArrayList and ArrayHash. This was required because now that the fields are also serializing values, the h
Arr field class into two: ArrayList and ArrayHash. This was required because now that the
fields are also serializing values, the handling of empty values is different depending on whether it is a list (empty
array) or a hash (empty array converted to null).withUriFieldName() method. Alternatively, the retainFieldName() method can be used to retain the field name as-is.Initial release.
Initial release.
Your coding agent can read these notes before it upgrades. Set up the MCP server →