Published 1/13/2024 · 3 min read
Laravel API resources let you shape the JSON responses your API returns. They sit between your models and the JSON output, giving you full control over what data is exposed and how it’s formatted.
Creating a Resource
Generate a resource with Artisan:
sail artisan make:resource UserResource
This creates app/Http/Resources/UserResource.php:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'avatar' => $this->avatar,
'email_verified_at' => $this->email_verified_at,
'is_admin' => $this->isAdmin(),
'created_at' => $this->created_at->toISOString(),
];
}
}
Using Resources
Return a single resource:
use App\Http\Resources\UserResource;
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return new UserResource($user);
});
This outputs:
{
"data": {
"id": 1,
"name": "Test User",
"email": "test@example.com",
"avatar": null,
"email_verified_at": "2024-01-01T00:00:00.000000Z",
"is_admin": false,
"created_at": "2024-01-01T00:00:00.000000Z"
}
}
Laravel automatically wraps the response in a data key, following the JSON:API specification.
Resource Collections
For multiple resources, use the collection method:
Route::get('/users', function () {
return UserResource::collection(User::all());
});
Pagination
Laravel’s pagination integrates seamlessly with resources:
Route::get('/users', function () {
return UserResource::collection(User::paginate(15));
});
This returns paginated data with metadata:
{
"data": [
{ "id": 1, "name": "User 1", ... },
{ "id": 2, "name": "User 2", ... }
],
"links": {
"first": "http://localhost/api/users?page=1",
"last": "http://localhost/api/users?page=5",
"prev": null,
"next": "http://localhost/api/users?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 5,
"path": "http://localhost/api/users",
"per_page": 15,
"to": 15,
"total": 75
}
}
Conditional Attributes
Include attributes only when certain conditions are met:
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
// Only include for the authenticated user viewing their own profile
'is_admin' => $this->when(
$request->user()?->id === $this->id || $request->user()?->isAdmin(),
$this->isAdmin()
),
// Only include if not null
'avatar' => $this->whenNotNull($this->avatar),
// Only include when the relationship is loaded
'posts' => PostResource::collection($this->whenLoaded('posts')),
];
}
Including Relationships
Load and include relationships:
// In your controller
return new UserResource(
User::with(['posts', 'comments'])->find($id)
);
// In your resource
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'posts' => PostResource::collection($this->whenLoaded('posts')),
'comments_count' => $this->whenCounted('comments'),
];
}
Resource Collections with Additional Data
Create a dedicated collection class for additional metadata:
sail artisan make:resource UserCollection
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
public function toArray(Request $request): array
{
return [
'data' => $this->collection,
'meta' => [
'total_admins' => $this->collection->where('is_admin', true)->count(),
],
];
}
}
Use it:
return new UserCollection(User::paginate(15));
Customizing the Wrapper
Remove the data wrapper for a specific resource:
public static $wrap = null;
Or globally in AppServiceProvider:
use Illuminate\Http\Resources\Json\JsonResource;
public function boot(): void
{
JsonResource::withoutWrapping();
}
Adding Meta Data
Add metadata to individual responses:
return (new UserResource($user))
->additional([
'meta' => [
'permissions' => $user->getAllPermissions(),
],
]);
Next up: Handling API errors gracefully in your Vue SPA.
Related Articles
- API Routes
Build backend endpoints with SvelteKit's +server.js files. Learn to handle HTTP methods, return JSON, and create REST APIs.
- What's Next
Continue your Svelte journey. Explore advanced topics, the ecosystem, and resources for going deeper with Svelte and SvelteKit.
- Your First x402 Server: Pay-Per-Request API
Build an Express API that requires Solana USDC payments. Return 402, verify payments, serve content.