All notable changes to this project will be documented in this file. This project adheres to Semantic Versioning and this changelog format.
- 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
withIncludePaths()
andwithSparseFieldSets()
methods, or using the conveniencewithQueryParameters()
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.
- BREAKING Methods relating to include paths and sparse field sets have been moved from the
Responses\Concerns\IsResponsable
trait to a newResponses\Concerns\HasEncodingParameters
trait. As part of this change, the previousprotected
methodfieldSets()
has been renamedsparseFieldSets()
. - BREAKING Made several changes to interfaces for sort fields:
- The
Attribute
andID
interfaces no longer implementSortable
and instead have aisSortable()
method directly defined on their interface. - The
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. - The
Schema::isSortable()
method has been renamedisSortField()
. This makes it clearer that the method is querying whether the provided name is a valid sort field. - The
Schema::sortable()
method has been renamedsortFields()
. This makes it clearer that the method is returning a list of the sort field names. - Added the
sortField()
andsortables()
methods to theSchema
interface.
- The
- The schema container now supports resolving schemas for models where the schema is registered against a parent class or interface. Parent classes are matched before interfaces, and if a match is found the resolution is cached to ensure the resolution logic runs once per model class.
- The resource factory class now looks up schemas for a model first, then retrieves the fully-qualified resource class from the matched schema. By delegating to the schema like this, the resource container can now convert models to resources where a schema has been registered for a parent class or interface.
- The
Contracts\Resources\Factory
interface now has acanCreate()
method to determine whether the factory can create a JSON:API resource for the supplied model. - The
Contracts\Schema\Container
interface now has aexistsForModel()
method, to determine whether a schema exists for the supplied model class.
- The
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, theContainer::attach()
method was also removed. - The
Core\Resources\Factory
class constructor was amended to only expect a schema container. Additionally the method signature of the protectedbuild()
method was changed to receive a schema instance and the model being converted to a JSON:API resource. - The
Core\Server\Server
andCore\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 useapp()->environment()
(which used to be the case as the injection was only type-hinted as the container contract).
- The base
Server
class now correctly passes extra parameters in itsurl()
method. Previously these were passed to Laravel'surl()
helper - but that helper only appends extra parameters if there is no HTTP host in the provided path. The server'surl()
method now passes these as we always went them appended, regardless of whether the API's base path has a HTTP host or not. - Include paths, sort fields and countable paths now correctly parse empty values. Previously an error was caused by attempting to cast an empty string to the relevant query objects.
- The
Core\Server\Server::$container
property is deprecated and will be removed in1.0.0-stable
. Child classes should use the newServer::$app
property instead.
- The
Contracts\Resources\Factory::handles()
method has been removed in favour of using the newcanCreate()
method instead. - The
Contracts\Schema\Container::resources()
method has been removed, in favour of resource factories using the schema container'sexistsForModel()
andschemaForModel()
methods.
- BREAKING Added the following methods to the
Contracts\Schema\Schema
interface:isFilter()
,isSparseField
,isSortable()
andhasSelfLink()
. 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. - BREAKING Made the following changes to the
Contracts\Query\QueryParameters
interface:- New
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. - The
filters
method now returns aFilterParameters
object or null. Previously it returned an array or null.
- New
- BREAKING The
$baseUri
argument on theContracts\Resources\Serializer\Relation
interface is now nullable. - BREAKING The
Contracts\Store\Store
interface now has afindOrFail
method. This is unlikely to be breaking in most implementations because theCore\Store\Store
class will be in use and has been updated. - BREAKING Added a
cast
method to theContracts\Resources\Container
interface. This is unlikely to be breaking in most implementations because theCore\Resources\Container
class will be in use and has been updated. - New
Contracts\Schema\IdEncoder
interface to encode model IDs to JSON:API resource IDs. - New
FilterParameters
class for handling a collection of filter parameters received from a client. - The
FieldSets
,IncludePaths
andSortFields
classes all now have acollect()
method, that returns a collection object. - The
IncludePaths
andSortFields
classes now havefilter
,reject
andforSchema
methods. - The
SortField
class now has staticascending
anddescending
methods, to easily create a sort field with the specified direction. - The
QueryParameters
class now has atoQuery()
method, that casts the value back to a HTTP query parameter array. This is different fromQueryParameters::toArray()
, as theinclude
andsort
parameters are strings in a HTTP query array. - The
QueryParameters
class now has aforSchema()
method, that returns a new query parameters instance that contains only parameters valid for the supplied schema. - The
Document\ResourceObject
class has a newwithRelationshipMeta
method for adding meta for a specified relationship. - Added new response classes for returning related resources for a relationship - e.g. the
/api/posts/1/comments
endpoint. Previously theDataResponse
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. - The core package now supports the countable implementation-semantic. This adds a custom query parameter that allows a client to specify which relationships should have a count added to their relationship meta.
- Added a number of pagination traits -
HasPageMeta
andHasPageNumbers
, so that these can be used in both the Eloquent and non-Eloquent implementations. - Added a
dump
method to theCore\Document\ResourceObject
class.
- BREAKING The return type of
Contracts\Schema\Schema::repository()
is now nullable. - BREAKING The return type of
Contracts\Store\Store::resources()
is now nullable. - BREAKING Made a number of changes to store contracts, so that the contracts are easier to implement in when not
working with Eloquent resources:
- The
QueryAllBuilder
contract has been removed; support for singular filters is now implemented via theHasSingularFilters
interface which is intended to be added to classes implementingQueryManyBuilder
. As part of this change, theQueriesAll::queryAll()
method now has theQueryManyBuilder
interface as its return type. - The
QueryManyBuilder
contract no longer has pagination methods on it. If a builder supports pagination, it must add theHasPagination
interface. - Removed the
cursor
method from theQueryManyBuilder
contract, as it is not required on the contract (implementing classes can add it if needed). Theget
method now has a return type ofiterable
instead of the LaravelCollection
class.
- The
- BREAKING The
Contracts\Encoder\Encoder
interface now has two methods for encoding resource identifiers:withToOne
andwithToMany
. These replace thewithIdentifiers
method, which has been removed. - Moved the following classes from the
Core\Responses
namespace to theCore\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 theCore\Responses
namespace):PaginatedResourceResponse
ResourceCollectionResponse
ResourceIdentifierCollectionResponse
ResourceIdentifierResponse
ResourceResponse
- Deleted the
Core\Responses\Concerns\EncodesIdentifiers
trait. This is considered non-breaking as the trait was only intended for internal use.
- The
QueryParameters::setFieldSet()
method now correctly passes the fields lists as an array to the field set constructor. - Fixed the
Core\Document\ResourceObject::merge()
method handling of merging relationships. Previously this usedarray_replace_recursive
to megre the relationship object, but this led to incorrect merging ofdata
members, particularly for to-many relationships. This has been altered toarray_replace
, so that thedata
,links
andmeta
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. - The default value of the
Resources\Relation
class is now returned by a protectedvalue
method, allowing child classes to modify the default behaviour if needed. - New
Creatable
interface, which theJsonApiResource
class delegates to when determining whether a resource was created within the current HTTP request.
- The
$container
property on theServer
class is nowprotected
and can be used by child classes if needed. - The
$resource
property on theResources\Relation
class is nowprotected
.
- Reverted #3 Server classes can no longer use constructor dependency injection. This is because server classes are created in a number of different contexts - e.g. HTTP requests, Artisan generators, etc - so injecting dependencies via the constructor will likely result in developers injecting dependencies that are only required in certain contexts in which the server is being used. See laravel #44 for discussion on this topic.
- The
Server\Server
contract no longer has aserving()
method on it. This has been removed from the contract so that developers can type-hint dependencies in theirserving
method.
- BREAKING The builder interfaces in the
Contracts\Store
namespace now have awithRequest
method. This allows passing the request into the builder process as context for the action. - BREAKING The
Contracts\Routing\Route
contract now has anauthorizer
method, for getting the authorizer instance for the route. - BREAKING The
Contracts\Schema\Schema
contract now has aurl
method, for generating a URL for the resource that the schema defines. - BREAKING Added the
allInverse()
method to theContracts\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. - New
get
method on theConditionalField
class for retrieving the value of the field. - Response classes now have a
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. - New
MetaResponse
class for returning a JSON:API response with a document containing a top-levelmeta
value. - #3 Server classes are now resolved via the service container, allowing the developer to use constructor dependency injection if desired.
- The
DataResponse
class now has adidntCreate
method for ensure the resource response does not have a201 Created
status.
- BREAKING The
Contracts\Auth\Authorizer
contract now requires the model class to be passed as the second argument on theindex
andstore
methods. Also, all methods have been updated to type-hint the Illuminate request object. - BREAKING The
using
method has been renamed towithQuery
on the following interfaces in theContracts\Store
namespace:QueryManyBuilder
QueryOneBuilder
ResourceBuilder
ToManyBuilder
ToOneBuilder
- BREAKING The
Contracts\Resources\Serializer\Hideable
contract has been updated to type-hint the request class in its method signatures. - BREAKING The
Core\Schema\SchemaAware
trait has been moved to theCore\Schema\Concerns
namespace, for consistency with other traits. - BREAKING The
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. - BREAKING The constructor argument for the abstract
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. - The server repository now caches servers it has created, and should now be registered in the service container as a singleton.
- Fixed parsing the
fields
query parameter to theCore\Query\FieldSets
andCore\Query\FieldSet
classes.
- BREAKING The
Contracts\Schema\Relation
contract now has aisValidated()
method, to determine if the relation value should be merged when validating update requests. There is now aCore\Schema\Concerns\RequiredForValidation
trait that can be used on relationship fields to implement the required method. - New features for the
Core\Documents\ResourceObject
class:- New
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. - The
putRelation
andreplace
methods now accept an instance ofUrlRoutable
for theid
value of to-one or to-many relations.
- New
- The schema container instance is now injected into schema classes via the constructor
$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. - New
Core\Resources\ConditionalList
class, for iterating over conditional attributes but yielding them as a zero-indexed array list.
- The
Core\Document\ResourceObject::withoutLinks()
method now correctly removes both resource links and relationship links. - BREAKING As conditional values are now supported in relationships (previously only supported in attributes), the
following have been renamed to make it clear that they are not just for use in attributes:
- The
Core\Resources\Concerns\ConditionallyLoadsAttributes
trait is nowConditionallyLoadsFields
. - The
Core\Resources\ConditionalAttr
is nowConditionalField
. - The
Core\Resources\ConditionalAttrs
is nowConditionalFields
.
- The
- BREAKING The first argument on the
Contracts\Server\Server
interface ($parameters
) has been made optional.
- BREAKING Removed the
mustValidate()
andisValidated()
methods from theCore\Resources\Relation
class. These fields are now defined on the schema's relation field instead of the resource's relation. - BREAKING Made changes to the
Core\Documents\ResourceObject
class:- Removed the deprecated
create()
method, as this was never intended to be brought in from the old package. - Remove the
Arrayable
contract (and therefore thetoArray()
method). This is becausetoArray()
was always ambiguous - would it return the field values, or the JSON representation of the resource? ReplacetoArray()
withjsonSerialize()
. Theall()
method continues to return the field values.
- Removed the deprecated
- #2
BREAKING The
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 theJsonApiResource
when no specific resource class exists. Schema fields must implement theContracts\Resources\Serializer\Attribute
andContracts\Resources\Serializer\Relation
interfaces on their fields for the serialization to work. - BREAKING The
Contracts\Encoder\Encoder
contract now has awithRequest
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 theirtoResponse()
methods. - BREAKING The
Contracts\Schema\Container
contract now has aschemaForModel
method to lookup a schema by providing either a model instance, or the fully-qualified class name of a model. - BREAKING The
Contracts\Schema\ID
contract now has akey()
method, that can return the model key for the ID. - BREAKING The
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 theid
value.
- New
Contracts\Resources\JsonApiRelation
contract for the relation object returned by theJsonApiResource::relationships()
method. This has the methods on it that encoders can rely on when encoding the relationship to JSON. - BREAKING The
Contracts\Schema\Relation
contract now has auriName()
method for retrieving the relationship's field name as it appears in a URI. TheJsonApiResource
class now automatically injects this value from the schema field into the resource relation object. - New
Core\Resources\ConditionalIterator
class for iterating over values that could contain conditional attributes.
- BREAKING The
attributes
,relationships
,meta
andlinks
method of theJsonApiResource
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 benull
to cater for resource encoding outside of HTTP requests (e.g. queued broadcasting). Additionally, therelationship
method return type has been changed to the newContracts\Resources\JsonApiResource
contract. - BREAKING The
exists
andcreate
methods on theContracts\Resources\Container
contract now correctly type-hint the parameter as anobject
. - BREAKING The
createResource
method on theContracts\Resources\Factory
contract now correctly type-hints the parameter as anobject
. - BREAKING The constructor of the
Core\Resources\Factory
class now expects a schema container and an optional array of resource bindings (instead of an iterable). If anull
value is provided for the bindings, the bindings will be retrieved from the schema container. Additionally, the protectedbuild
method signature has been updated to correctly type-hint the second argument as anobject
. - BREAKING The constructor arguments for the
Core\Resources\Relation
class have been changed so that it now receives the model and base URI - rather than theJsonApiResource
object. This change was made so that it can be used more broadly.
- BREAKING The
attach
andattachAll
methods of theCore\Resources\Factory
class have been removed, because they were not in use.
Initial release.