Index Endpoint
The Index endpoint handles GET requests to the collection root (e.g. GET /posts) and responds with a JSON:API document containing a collection of resources.
To enable it for a resource or collection, add an instance of the Index endpoint to the endpoints array:
use Tobyz\JsonApiServer\Endpoint\Index;
class PostsResource extends Resource
{
// ...
public function endpoints(): array
{
return [Index::make()];
}
}Authorization
If you want to restrict the ability to list resources, use the visible or hidden method, with a closure that returns a boolean value:
Index::make()->visible(
fn(Context $context) => $context->request->getAttribute('isAdmin'),
);Implementation
The Index endpoint requires the resource or collection to implement the Tobyz\JsonApiServer\Resource\Listable interface. The endpoint will:
- Call the
querymethod to create a query object. - Apply filters, sorts, and pagination to the query object.
- Call the
resultsmethod to retrieve results from the query.
An example implementation might look like:
use App\Models\Post;
use Tobyz\JsonApiServer\Context;
use Tobyz\JsonApiServer\Resource\{Listable, AbstractResource};
class PostsResource extends AbstractResource implements Listable
{
// ...
public function query(Context $context): object
{
return Post::query();
}
public function results(object $query, Context $context): array
{
return $query->get();
}
}Laravel Integration
For Laravel applications with Eloquent-backed resources, you can extend the Tobyz\JsonApiServer\Laravel\EloquentResource class which implements this interface for you. Learn more on the Laravel Integration page.
Sorting
The JSON:API specification reserves the sort query parameter for sorting resources. Multiple sort fields are comma-separated, and a - prefix indicates descending order. For example, the following request would list posts sorted by title ascending, then createdAt descending:
GET /posts?sort=title,-createdAtTo define sort fields that can be used in this query parameter, add them to your resource's sorts method:
class PostsResource extends Resource implements Listable
{
// ...
public function sorts(): array
{
return [
ExampleSort::make('example'),
];
}
}Laravel Integration
For Eloquent-backed resources, a number of sort fields are provided to make it easy to implement sorting on your resource.
Inline Sort Fields
The easiest way to define a custom sort field is to use the CustomSort class, which accepts the name of the sort field and a callback to apply the sort to the query:
use Tobyz\JsonApiServer\Schema\CustomSort;
CustomSort::make('example', function (
$query,
string $direction,
Context $context,
) {
$query->orderBy('example', $direction);
});Writing Sort Fields
To create your own sort field class, extend the Tobyz\JsonApiServer\Schema\Sort class and implement the apply method:
use Tobyz\JsonApiServer\Context;
use Tobyz\JsonApiServer\Schema\Sort;
class SortColumn extends Sort
{
public function apply(
object $query,
string $direction,
Context $context,
): void {
$query->orderBy($this->name, $direction);
}
}Visibility
If you want to restrict the ability to use a sort field, use the visible or hidden method, passing a closure that returns a boolean value:
SortColumn::make('example')->visible(
fn(Context $context) => $context->request->getAttribute('isAdmin'),
);Default Sort
You can set a default sort to be used when none is specified by the client. To do this, use the defaultSort method on the Index endpoint:
Index::make()->defaultSort('-createdAt,title');Filtering
The JSON:API specification reserves the filter query parameter for filtering resources.
To define filters that can be used in this query parameter, add them to your resource's filters method:
class PostsResource extends Resource implements Listable
{
// ...
public function filters(): array
{
return [
ExampleFilter::make('example'),
];
}
}Laravel Integration
For Eloquent-backed resources, a number of filters are provided to make it easy to implement filtering on your resource.
Inline Filters
The easiest way to define a filter is to use the CustomFilter class, which accepts the name of the filter parameter and a callback to apply the filter to the query. The value received by a filter can be a string or an array, so you will need to handle both:
use Tobyz\JsonApiServer\Schema\CustomFilter;
CustomFilter::make('name', function (
$query,
string|array $value,
Context $context,
) {
$query->whereIn('name', (array) $value);
});Now the filter can be applied like so:
GET /posts?filter[name]=Toby
GET /posts?filter[name][]=Toby&filter[name][]=FranzWriting Filters
To create your own filter class, extend the Tobyz\JsonApiServer\Schema\Filter class and implement the apply method:
use Tobyz\JsonApiServer\Context;
use Tobyz\JsonApiServer\Schema\Filter;
class WhereIn extends Filter
{
public function apply(
object $query,
string|array $value,
Context $context,
): void {
$query->whereIn($this->name, $value);
}
}Visibility
If you want to restrict the ability to use a filter, use the visible or hidden method, passing a closure that returns a boolean value:
WhereIn::make('example')->visible(
fn(Context $context) => $context->request->getAttribute('isAdmin'),
);Pagination
The JSON:API specification reserves the page query parameter for paginating collections. The specification is agnostic about the pagination strategy used by the server.
Currently json-api-server supports an offset pagination strategy, using the page[limit] and page[offset] query parameters. Support for cursor pagination is planned.
Offset Pagination
In order to use offset pagination for your resource listing, call the paginate method on the Index endpoint:
Index::make()->paginate();The default page limit is 20 and the maximum limit that a client can request is 50. If you would like to use different values, pass them as arguments to the paginate method:
Index::make()->paginate(10, 100);You will also need to implement the Tobyz\JsonApiServer\Resource\Paginatable interface on your resource and specify how the limit and offset values should be applied to your query:
use Tobyz\JsonApiServer\Context;
use Tobyz\JsonApiServer\Pagination\OffsetPagination;
use Tobyz\JsonApiServer\Resource\{Listable, Paginatable, AbstractResource};
class PostsResource extends AbstractResource implements Listable, Paginatable
{
// ...
public function paginate(object $query, OffsetPagination $pagination): void
{
$query->offset($pagination->offset)->limit($pagination->limit);
}
}Countability
By default, offset pagination won't include a last link because there is no way to know the total number of resources.
If you would like to include a last link, as well as include the total number of resources as meta information, you can implement the Tobyz\JsonApiServer\Resource\Countable interface on your resource:
use Tobyz\JsonApiServer\Context;
use Tobyz\JsonApiServer\Pagination\OffsetPagination;
use Tobyz\JsonApiServer\Resource\{
Countable,
Listable,
Paginatable,
AbstractResource,
};
class PostsResource extends AbstractResource implements
Listable,
Paginatable,
Countable
{
// ...
public function count(object $query, Context $context): int
{
return $query->count();
}
}