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
query
method to create a query object. - Apply filters, sorts, and pagination to the query object.
- Call the
results
method 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,-createdAt
To 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][]=Franz
Writing 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();
}
}