Eloquent: API 리소스

업데이트됨

번역일: 2026년 6월 25일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 6월 20일
번역 갱신
2026년 6월 25일

Eloquent: API 리소스

소개

API를 개발할 때, Eloquent 모델과 실제로 클라이언트에 반환되는 JSON 응답 사이에 변환 레이어가 필요한 경우가 있습니다. 예를 들어, 특정 사용자에게만 일부 속성을 노출하거나, 모델의 JSON 표현에 항상 특정 관계를 포함시키고 싶을 수 있습니다. Eloquent의 리소스 클래스를 사용하면 모델과 모델 컬렉션을 JSON으로 변환하는 과정을 간결하고 유연하게 제어할 수 있습니다.

물론 toJson 메서드로 Eloquent 모델이나 컬렉션을 JSON으로 변환할 수도 있지만, 리소스 클래스는 모델과 그 관계의 JSON 직렬화를 훨씬 세밀하고 체계적으로 다룰 수 있게 해줍니다.

리소스 생성

make:resource Artisan 명령어로 리소스 클래스를 생성할 수 있습니다. 생성된 리소스 파일은 기본적으로 app/Http/Resources 디렉토리에 위치하며, Illuminate\Http\Resources\Json\JsonResource 클래스를 상속합니다.

php artisan make:resource UserResource

리소스 컬렉션

개별 모델을 변환하는 리소스 외에, 모델 컬렉션 전체를 변환하는 리소스 컬렉션도 생성할 수 있습니다. 컬렉션 리소스를 사용하면 응답에 페이지네이션 링크나 컬렉션 전체에 관한 메타 정보를 포함시킬 수 있습니다.

리소스 컬렉션을 생성하려면 --collection 플래그를 사용하거나, 클래스 이름에 Collection을 포함시키면 됩니다. 컬렉션 리소스는 Illuminate\Http\Resources\Json\ResourceCollection 클래스를 상속합니다.

php artisan make:resource User --collectionphp artisan make:resource UserCollection

개념 개요

NOTE

이 섹션은 리소스와 리소스 컬렉션에 대한 고수준 개요입니다. 리소스가 제공하는 다양한 커스터마이징 기능을 더 깊이 이해하려면, 이후 섹션들을 계속 읽어보시길 권장합니다.

구체적인 옵션들을 살펴보기 전에, Laravel에서 리소스가 어떻게 동작하는지 전체적인 흐름을 먼저 파악해봅시다.

리소스 클래스는 하나의 모델을 JSON 구조로 변환하는 역할을 합니다. 예를 들어, 간단한 UserResource 클래스는 다음과 같습니다.

<?php namespace App\Http\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class UserResource extends JsonResource { /** * 리소스를 배열로 변환합니다. * * @return array<string, mixed> */ public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; } }

모든 리소스 클래스는 toArray 메서드를 정의하며, 이 메서드가 반환하는 배열이 JSON 응답으로 변환됩니다.

$this를 통해 모델 프로퍼티에 직접 접근할 수 있습니다. 리소스 클래스는 내부적으로 프로퍼티와 메서드 접근을 자동으로 모델에 위임하기 때문입니다.

리소스를 정의한 후에는 라우트나 컨트롤러에서 반환할 수 있습니다. 리소스 생성자에 모델 인스턴스를 전달하면 됩니다.

use App\Http\Resources\UserResource; use App\Models\User; Route::get('/user/{id}', function (string $id) { return new UserResource(User::findOrFail($id)); });

편의상, 모델의 toResource 메서드를 사용할 수도 있습니다. 이 메서드는 프레임워크 규칙에 따라 모델에 대응하는 리소스 클래스를 자동으로 찾아줍니다.

return User::findOrFail($id)->toResource();

toResource 메서드를 호출하면, Laravel은 모델 이름을 기반으로 Http\Resources 네임스페이스에서 Resource 접미사가 붙은 클래스를 찾으려 시도합니다.

리소스 클래스가 이 명명 규칙을 따르지 않거나 다른 네임스페이스에 위치한 경우, UseResource 속성(attribute)으로 기본 리소스를 명시할 수 있습니다.

<?php namespace App\Models; use App\Http\Resources\CustomUserResource; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Attributes\UseResource; #[UseResource(CustomUserResource::class)] class User extends Model { // ... }

또는 toResource 메서드에 리소스 클래스를 직접 전달할 수도 있습니다.

return User::findOrFail($id)->toResource(CustomUserResource::class);

리소스 컬렉션

컬렉션 형태의 리소스나 페이지네이션 응답을 반환할 때는, 리소스 클래스의 collection 메서드를 사용하세요.

use App\Http\Resources\UserResource; use App\Models\User; Route::get('/users', function () { return UserResource::collection(User::all()); });

편의상, Eloquent 컬렉션의 toResourceCollection 메서드를 사용할 수도 있습니다. 이 메서드는 프레임워크 규칙에 따라 대응하는 리소스 컬렉션 클래스를 자동으로 찾아줍니다.

return User::all()->toResourceCollection();

toResourceCollection 메서드를 호출하면, Laravel은 모델 이름에 Collection 접미사가 붙은 리소스 컬렉션 클래스를 Http\Resources 네임스페이스에서 찾으려 시도합니다.

리소스 컬렉션 클래스가 이 명명 규칙을 따르지 않거나 다른 네임스페이스에 위치한 경우, UseResourceCollection 속성으로 기본 리소스 컬렉션을 명시할 수 있습니다.

<?php namespace App\Models; use App\Http\Resources\CustomUserCollection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Attributes\UseResourceCollection; #[UseResourceCollection(CustomUserCollection::class)] class User extends Model { // ... }

또는 toResourceCollection 메서드에 리소스 컬렉션 클래스를 직접 전달할 수도 있습니다.

return User::all()->toResourceCollection(CustomUserCollection::class);

커스텀 리소스 컬렉션

기본적으로 리소스 컬렉션은 커스텀 메타 데이터를 추가할 수 없습니다. 컬렉션 응답을 직접 커스터마이징하려면 전용 리소스 컬렉션 클래스를 생성하세요.

php artisan make:resource UserCollection

생성된 클래스에서 응답에 포함할 메타 데이터를 자유롭게 정의할 수 있습니다.

<?php namespace App\Http\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\ResourceCollection; class UserCollection extends ResourceCollection { /** * 리소스 컬렉션을 배열로 변환합니다. * * @return array<int|string, mixed> */ public function toArray(Request $request): array { return [ 'data' => $this->collection, 'links' => [ 'self' => 'link-value', ], ]; } }

이렇게 정의한 리소스 컬렉션은 라우트나 컨트롤러에서 반환할 수 있습니다.

use App\Http\Resources\UserCollection; use App\Models\User; Route::get('/users', function () { return new UserCollection(User::all()); });

또는 toResourceCollection 메서드를 편의상 활용할 수도 있습니다. Laravel은 모델 이름에 Collection 접미사가 붙은 클래스를 자동으로 찾아줍니다.

return User::all()->toResourceCollection();

컬렉션 키 보존

라우트에서 리소스 컬렉션을 반환하면 Laravel은 기본적으로 컬렉션의 키를 숫자 순서로 초기화합니다. 원래 키를 유지하고 싶다면 리소스 클래스에 PreserveKeys 속성을 추가하세요.

<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Attributes\PreserveKeys; use Illuminate\Http\Resources\Json\JsonResource; #[PreserveKeys] class UserResource extends JsonResource { // ... }

PreserveKeys 속성이 적용되면, 라우트나 컨트롤러에서 컬렉션을 반환할 때 원래 키가 유지됩니다.

use App\Http\Resources\UserResource; use App\Models\User; Route::get('/users', function () { return UserResource::collection(User::all()->keyBy->id); });

기본 리소스 클래스 커스터마이징

리소스 컬렉션의 $this->collection 프로퍼티는 기본적으로, 컬렉션의 각 항목을 단일 리소스 클래스에 매핑한 결과로 자동 채워집니다. 단일 리소스 클래스는 컬렉션 클래스 이름에서 Collection 접미사를 제거한 이름으로 추정됩니다.

예를 들어, UserCollection은 각 사용자 인스턴스를 UserResource에 매핑하려 시도합니다. 이 동작을 커스터마이징하려면 Collects 속성을 사용하세요.

<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Attributes\Collects; use Illuminate\Http\Resources\Json\ResourceCollection; #[Collects(Member::class)] class UserCollection extends ResourceCollection { // ... }

리소스 작성

NOTE

아직 개념 개요를 읽지 않으셨다면, 먼저 읽어보시길 권장합니다.

리소스의 핵심은 모델을 배열로 변환하는 것입니다. 각 리소스는 toArray 메서드를 통해 모델의 속성을 API 친화적인 배열로 반환하며, 이 배열이 라우트나 컨트롤러에서 JSON 응답으로 전송됩니다.

<?php namespace App\Http\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class UserResource extends JsonResource { /** * 리소스를 배열로 변환합니다. * * @return array<string, mixed> */ public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; } }

리소스를 정의한 후에는 라우트나 컨트롤러에서 직접 반환할 수 있습니다.

use App\Models\User; Route::get('/user/{id}', function (string $id) { return User::findOrFail($id)->toUserResource(); });

관계 포함

응답에 연관 리소스를 포함시키려면, toArray 메서드가 반환하는 배열에 해당 관계를 추가하면 됩니다. 아래 예시에서는 PostResourcecollection 메서드를 사용해 사용자의 블로그 게시글을 응답에 추가합니다.

use App\Http\Resources\PostResource; use Illuminate\Http\Request; /** * 리소스를 배열로 변환합니다. * * @return array<string, mixed> */ public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'posts' => PostResource::collection($this->posts), 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; }

NOTE

이미 로드된 관계만 포함하고 싶다면 조건부 관계 문서를 참고하세요.

리소스 컬렉션

단일 리소스가 하나의 모델을 배열로 변환한다면, 리소스 컬렉션은 모델 컬렉션 전체를 배열로 변환합니다. 모든 Eloquent 모델 컬렉션은 toResourceCollection 메서드를 제공하므로, 별도의 리소스 컬렉션 클래스를 반드시 정의하지 않아도 됩니다.

use App\Models\User; Route::get('/users', function () { return User::all()->toResourceCollection(); });

단, 컬렉션과 함께 반환할 메타 데이터를 커스터마이징해야 한다면 별도의 리소스 컬렉션 클래스를 정의하세요.

<?php namespace App\Http\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\ResourceCollection; class UserCollection extends ResourceCollection { /** * 리소스 컬렉션을 배열로 변환합니다. * * @return array<string, mixed> */ public function toArray(Request $request): array { return [ 'data' => $this->collection, 'links' => [ 'self' => 'link-value', ], ]; } }

단일 리소스와 마찬가지로, 리소스 컬렉션도 라우트나 컨트롤러에서 직접 반환할 수 있습니다.

use App\Http\Resources\UserCollection; use App\Models\User; Route::get('/users', function () { return new UserCollection(User::all()); });

또는 toResourceCollection 메서드를 편의상 활용할 수 있습니다. Laravel은 모델 이름에 Collection 접미사가 붙은 리소스 컬렉션 클래스를 자동으로 찾아줍니다.

return User::all()->toResourceCollection();

데이터 래핑

기본적으로 리소스 응답이 JSON으로 변환될 때, 최외곽 리소스는 data 키로 감싸집니다. 예를 들어, 일반적인 리소스 컬렉션 응답은 다음과 같습니다.

{ "data": [ { "id": 1, "name": "홍길동", "email": "hong@example.com" }, { "id": 2, "name": "김철수", "email": "kim@example.com" } ] }

이 래핑을 비활성화하려면 Illuminate\Http\Resources\Json\JsonResourcewithoutWrapping 메서드를 호출하세요. 일반적으로 AppServiceProvider나 모든 요청에 로드되는 서비스 프로바이더boot 메서드에서 호출합니다.

<?php namespace App\Providers; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * 애플리케이션 서비스를 등록합니다. */ public function register(): void { // ... } /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { JsonResource::withoutWrapping(); } }

WARNING

withoutWrapping 메서드는 최외곽 응답에만 영향을 미칩니다. 직접 리소스 컬렉션에 수동으로 추가한 data 키는 제거되지 않습니다.

중첩 리소스 래핑

리소스의 관계가 어떻게 래핑될지는 자유롭게 결정할 수 있습니다. 중첩 여부와 관계없이 모든 리소스 컬렉션을 data 키로 감싸고 싶다면, 각 리소스에 대한 리소스 컬렉션 클래스를 정의하고 data 키 안에 컬렉션을 반환하면 됩니다.

이렇게 하면 최외곽 리소스가 data 키로 두 번 감싸지는 것이 아닐지 걱정될 수 있습니다. 하지만 Laravel은 리소스가 실수로 이중으로 래핑되는 것을 방지하므로 걱정하지 않아도 됩니다.

<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class CommentsCollection extends ResourceCollection { /** * 리소스 컬렉션을 배열로 변환합니다. * * @return array<string, mixed> */ public function toArray(Request $request): array { return ['data' => $this->collection]; } }

데이터 래핑과 페이지네이션

리소스 응답을 통해 페이지네이션된 컬렉션을 반환할 때, withoutWrapping 메서드를 호출했더라도 Laravel은 항상 리소스 데이터를 data 키로 감쌉니다. 페이지네이션 응답에는 페이지네이터 상태에 관한 metalinks 키가 반드시 포함되기 때문입니다.

{ "data": [ { "id": 1, "name": "홍길동", "email": "hong@example.com" }, { "id": 2, "name": "김철수", "email": "kim@example.com" } ], "links":{ "first": "http://example.com/users?page=1", "last": "http://example.com/users?page=1", "prev": null, "next": null }, "meta":{ "current_page": 1, "from": 1, "last_page": 1, "path": "http://example.com/users", "per_page": 15, "to": 10, "total": 10 } }

페이지네이션

Laravel 페이지네이터 인스턴스를 리소스의 collection 메서드나 커스텀 리소스 컬렉션에 전달할 수 있습니다.

use App\Http\Resources\UserCollection; use App\Models\User; Route::get('/users', function () { return new UserCollection(User::paginate()); });

편의상, 페이지네이터의 toResourceCollection 메서드를 사용할 수도 있습니다. Laravel은 프레임워크 규칙에 따라 대응하는 리소스 컬렉션 클래스를 자동으로 찾아줍니다.

return User::paginate()->toResourceCollection();

페이지네이션 응답에는 항상 페이지네이터 상태에 관한 metalinks 키가 포함됩니다.

{ "data": [ { "id": 1, "name": "홍길동", "email": "hong@example.com" }, { "id": 2, "name": "김철수", "email": "kim@example.com" } ], "links":{ "first": "http://example.com/users?page=1", "last": "http://example.com/users?page=1", "prev": null, "next": null }, "meta":{ "current_page": 1, "from": 1, "last_page": 1, "path": "http://example.com/users", "per_page": 15, "to": 10, "total": 10 } }

페이지네이션 정보 커스터마이징

페이지네이션 응답의 links 또는 meta 키에 포함되는 정보를 커스터마이징하려면, 리소스에 paginationInformation 메서드를 정의하세요. 이 메서드는 $paginated 데이터와 linksmeta 키를 포함하는 $default 배열을 인자로 받습니다.

/** * 리소스의 페이지네이션 정보를 커스터마이징합니다. * * @param \Illuminate\Http\Request $request * @param array $paginated * @param array $default * @return array */ public function paginationInformation($request, $paginated, $default) { $default['links']['custom'] = 'https://example.com'; return $default; }

조건부 속성

특정 조건이 충족될 때만 응답에 속성을 포함시키고 싶은 경우가 있습니다. 예를 들어, 현재 사용자가 관리자인 경우에만 특정 값을 반환하고 싶을 수 있습니다. Laravel은 이런 상황을 위해 다양한 헬퍼 메서드를 제공합니다. when 메서드를 사용하면 조건부로 속성을 응답에 추가할 수 있습니다.

/** * 리소스를 배열로 변환합니다. * * @return array<string, mixed> */ public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'secret' => $this->when($request->user()->isAdmin(), 'secret-value'), 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; }

이 예시에서 secret 키는 인증된 사용자의 isAdmin 메서드가 true를 반환할 때만 응답에 포함됩니다. false를 반환하면, 클라이언트에 전송되기 전에 secret 키가 응답에서 제거됩니다.

when 메서드의 두 번째 인자로 클로저를 전달하면, 조건이 true일 때만 값을 계산합니다.

'secret' => $this->when($request->user()->isAdmin(), function () { return 'secret-value'; }),

whenHas 메서드는 해당 속성이 실제로 모델에 존재할 때만 포함시킵니다.

'name' => $this->whenHas('name'),

whenNotNull 메서드는 속성값이 null이 아닐 때만 포함시킵니다.

'name' => $this->whenNotNull($this->name),

조건부 속성 병합

동일한 조건에서만 포함해야 하는 속성이 여러 개 있다면, mergeWhen 메서드를 사용해 조건이 true일 때 여러 속성을 한 번에 포함시킬 수 있습니다.

/** * 리소스를 배열로 변환합니다. * * @return array<string, mixed> */ public function toArray(Request $request): array { return [ 'id' =>

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 25일