Resource Collections

Resource Collections, Pagination, and Conditional Attributes

ProductResource::collection($products) maps a list through the resource. A class of your own, from make:resource ProductCollection --collection, can add top-level keys. Give it a paginator, and Laravel 2,157 adds links and meta blocks:

app/Http/Resources/ProductCollection.phpPHP
public function toArray(Request $request): array
{
    return ['data' => $this->collection];
}
public function with(Request $request): array
{
    return ['meta' => ['api_version' => 'v1']];
}
Output
$ curl -s "$B/api/v1/products?page=2" \
  | jq -c '[.data[].title], .links.prev, .links.next, (.meta | del(.path))'
["SQL That Scales","The Night Train"]
"http://127.0.0.1:8420/api/v1/products?page=1"
"http://127.0.0.1:8420/api/v1/products?page=3"
{"current_page":2,"from":3,"last_page":3,"per_page":2,"to":4,"total":5,"api_version":"v1"}

The with() meta merged into the paginator's, and a paginationInformation() method removed the page-link array. simplePaginate() skips the COUNT(*); cursorPaginate() suits feeds (Ordering and Pagination).

Conditional attributes let one resource serve every caller. when() in Eloquent API Resources showed stock only to a token with products:write. whenLoaded() includes a relation only if it was eager loaded, so a resource never causes an N+1 (Eager Loading). Its relatives are whenNotNull(), whenCounted(), whenPivotLoaded() and mergeWhen():

Output of 198
$ curl -s $B/api/v1/products/3 | jq -c '.data | del(.price, .category, .links)'
{"id":3,"sku":"BK-1003","title":"SQL That Scales","in_stock":false}
$ curl -s -H "Authorization: Bearer $BEN" $B/api/v1/products/3 \
  | jq -c '.data | del(.price, .category, .links)'
{"id":3,"sku":"BK-1003","title":"SQL That Scales","in_stock":false,"stock":0}

Resources also feed documentation. Scramble 2,214 (https://github.com/dedoc/scramble 2,214 ) 0.13.45 (composer require dedoc/scramble) infers an OpenAPI 3.1 document from routes, validation and toArray(), without annotations, and serves it locally at /docs/api.json with a viewer at /docs/api. Here it found all seven paths and typed stock as an integer and in_stock as a boolean. L5-Swagger 2,937 (https://github.com/DarkaOnLine/L5-Swagger 2,937 ) 11.1.0 is the annotation-based alternative.