Eloquent API Resources

Returning a model serializes every column, so a later migration can leak a column you never meant to publish. A resource (php artisan make:resource ProductResource) names each field and decouples the JSON from the schema. Here name goes out as title, and price becomes an object:

app/Http/Resources/ProductResource.php: toArray()PHP
public function toArray(Request $request): array
{
    return [
        'id' => $this->id,
        'sku' => $this->sku,
        'title' => $this->name,
        'price' => ['amount' => $this->price, 'currency' => 'USD'],
        'in_stock' => $this->stock > 0,
        'stock' => $this->when(
            $request->user('sanctum')?->tokenCan('products:write'), $this->stock),
        'category' => new CategoryResource($this->whenLoaded('category')),
        'links' => ['self' => route('v1.products.show', $this->resource)],
    ];
}
Output
$ curl -s $B/api/v1/products/2 \
  | jq -c '.data | {id, sku, title, price}, {in_stock, category}, .links'
{"id":2,"sku":"BK-1002","title":"Modern PHP","price":{"amount":34.5,"currency":"USD"}}
{"in_stock":true,"category":{"id":1,"name":"Computing"}}
{"self":"http://127.0.0.1:8420/api/v1/products/2"}

$this->name works because the resource forwards property access to the wrapped model, $this->resource. The object arrives inside data; JsonResource::withoutWrapping() removes the wrapper. $product->toResource() finds ProductResource by naming convention.