API 리소스

API를 구축할 때 데이터 모델을 클라이언트에 보내기 전에 일관된 형식으로 변환해야 하는 경우가 많습니다. 변환기를 통해 구현된 API 리소스는 엔터티, 배열 또는 개체를 구조화된 API 응답으로 변환하는 깔끔한 방법을 제공합니다. API를 통해 노출되는 데이터 구조와 내부 데이터 구조를 분리하는 데 도움이 되므로 시간이 지남에 따라 API를 더 쉽게 유지 관리하고 발전시킬 수 있습니다.

빠른 예

다음 예에서는 애플리케이션의 변환기에 대한 일반적인 사용 패턴을 보여줍니다.

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class UserTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'id'         => $resource['id'],
            'name'       => $resource['name'],
            'email'      => $resource['email'],
            'created_at' => $resource['created_at'],
        ];
    }
}

// In your controller
$user        = model('UserModel')->find(1);
$transformer = new UserTransformer();

return $this->respond($transformer->transform($user));

이 예에서 UserTransformer은 API 응답에 포함되어야 하는 사용자 엔터티의 필드를 정의합니다. transform() 메서드는 단일 리소스를 변환하는 반면 transformMany()는 리소스 컬렉션을 처리합니다.

변환기 만들기

변환기를 생성하려면 BaseTransformer 클래스를 확장하고 toArray() 메서드를 구현하여 API 리소스 구조를 정의하세요. toArray() 메서드는 변환되는 리소스를 매개변수로 수신하여 해당 데이터에 액세스하고 변환할 수 있도록 합니다.

기본 변압기

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class UserTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'id'           => $resource['id'],
            'username'     => $resource['name'],  // Renaming the field
            'email'        => $resource['email'],
            'member_since' => date('Y-m-d', strtotime($resource['created_at'])), // Formatting
        ];
    }
}

toArray() 메서드는 리소스(엔티티, 배열 또는 객체)를 매개변수로 수신하고 API 응답의 구조를 정의합니다. 리소스에서 원하는 필드를 포함할 수 있으며 필요에 따라 값의 이름을 바꾸거나 변환할 수도 있습니다.

변환기 파일 생성

CodeIgniter는 변환기 뼈대 파일을 빠르게 생성하기 위한 CLI 명령을 제공합니다.

php spark make:transformer User

이렇게 하면 기본 구조가 이미 있는 app/Transformers/User.php에 새 변환기 파일이 생성됩니다.

명령 옵션

make:transformer 명령은 여러 옵션을 지원합니다.

–접미사

클래스 이름에 “Transformer”를 추가합니다.

php spark make:transformer User --suffix

app/Transformers/UserTransformer.php를 생성합니다.

–네임스페이스

사용자 정의 루트 네임스페이스를 지정합니다.

php spark make:transformer User --namespace="MyCompany\\API"
–힘

기존 파일을 강제로 덮어씁니다.

php spark make:transformer User --force

하위 디렉터리

이름에 경로를 포함하여 변환기를 하위 디렉터리로 구성할 수 있습니다.

php spark make:transformer api/v1/User

그러면 적절한 네임스페이스 App\Transformers\Api\V1을 사용하여 app/Transformers/Api/V1/User.php가 생성됩니다.

컨트롤러에서 Transformer 사용

변환기를 만든 후에는 클라이언트에 반환하기 전에 컨트롤러에서 이를 사용하여 데이터를 변환할 수 있습니다.

<?php

namespace App\Controllers;

use App\Transformers\UserTransformer;
use CodeIgniter\API\ResponseTrait;

class Users extends BaseController
{
    use ResponseTrait;

    public function show($id)
    {
        $user = model('UserModel')->find($id);

        if (! $user) {
            return $this->failNotFound('User not found');
        }

        $transformer = new UserTransformer();

        return $this->respond($transformer->transform($user));
    }

    public function index()
    {
        $users = model('UserModel')->findAll();

        $transformer = new UserTransformer();

        return $this->respond($transformer->transformMany($users));
    }
}

필드 필터링

변환기는 현재 URL의 fields 쿼리 매개변수를 통해 필드 필터링을 자동으로 지원합니다. 이를 통해 API 클라이언트는 필요한 특정 필드만 요청할 수 있으므로 대역폭이 줄어들고 성능이 향상됩니다.

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class UserTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'id'         => $resource['id'],
            'name'       => $resource['name'],
            'email'      => $resource['email'],
            'created_at' => $resource['created_at'],
            'updated_at' => $resource['updated_at'],
        ];
    }
}

// Request: GET /users/1?fields=id,name
// Response: {"id": 1, "name": "John Doe"}

/users/1?fields=id,name에 대한 요청은 다음만 반환합니다.

{
    "id": 1,
    "name": "John Doe"
}

사용 가능한 필드 제한

기본적으로 클라이언트는 toArray() 메서드에 정의된 모든 필드를 요청할 수 있습니다. getAllowedFields() 메소드를 재정의하여 허용되는 필드를 제한할 수 있습니다.

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class UserTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'id'         => $resource['id'],
            'name'       => $resource['name'],
            'email'      => $resource['email'],
            'created_at' => $resource['created_at'],
            'updated_at' => $resource['updated_at'],
        ];
    }

    protected function getAllowedFields(): ?array
    {
        // Only these fields can be requested
        return ['id', 'name', 'created_at'];
    }
}

이제 클라이언트가 /users/1?fields=email을 요청하더라도 email이 허용된 필드 목록에 없기 때문에 ApiException이 발생합니다.

컬렉션의 변화

transformMany() 메서드를 사용하면 리소스 배열을 쉽게 변환할 수 있습니다.

<?php

namespace App\Controllers;

use App\Transformers\UserTransformer;
use CodeIgniter\API\ResponseTrait;

class Users extends BaseController
{
    use ResponseTrait;

    public function index()
    {
        $users = model('UserModel')->findAll();

        $transformer = new UserTransformer();
        $data        = $transformer->transformMany($users);

        return $this->respond($data);
    }
}

transformMany() 메서드는 요청에 지정된 필드 필터링 또는 포함을 포함하여 컬렉션의 각 항목에 동일한 변환 논리를 적용합니다.

다양한 데이터 유형 작업

변환기는 엔터티뿐만 아니라 다양한 데이터 유형을 처리할 수 있습니다.

엔터티 변환

Entity 인스턴스를 transform()에 전달하면 자동으로 엔터티의 toArray() 메서드를 호출하여 데이터를 가져옵니다.

<?php

use App\Entities\User;
use App\Transformers\UserTransformer;

$user = new User([
    'id'    => 1,
    'name'  => 'John Doe',
    'email' => 'john@example.com',
]);

$transformer = new UserTransformer();
$result      = $transformer->transform($user);

배열 변환

일반 배열도 변환할 수 있습니다.

<?php

use App\Transformers\UserTransformer;

$userData = [
    'id'    => 1,
    'name'  => 'John Doe',
    'email' => 'john@example.com',
];

$transformer = new UserTransformer();
$result      = $transformer->transform($userData);

객체 변형

모든 객체를 배열로 캐스팅하고 변환할 수 있습니다.

<?php

use App\Transformers\UserTransformer;

$user        = new \stdClass();
$user->id    = 1;
$user->name  = 'John Doe';
$user->email = 'john@example.com';

$transformer = new UserTransformer();
$result      = $transformer->transform($user);

toArray()만 사용

transform()에 리소스를 전달하지 않으면 toArray() 메서드의 데이터가 사용됩니다.

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class StaticDataTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'version' => '1.0',
            'status'  => 'active',
            'message' => 'API is running',
        ];
    }
}

// Usage
$transformer = new StaticDataTransformer();
$result      = $transformer->transform(null); // No resource passed

수업 참고자료

class CodeIgniter\API\BaseTransformer
__construct(?IncomingRequest $request = null)
매개변수:
  • $request (IncomingRequest|null) – 선택적 요청 인스턴스. 제공되지 않으면 전역 요청이 사용됩니다.

변환기를 초기화하고 요청에서 fieldsinclude 쿼리 매개변수를 추출합니다.

toArray(mixed $resource)
매개변수:
  • $resource (mixed) – 변환되는 리소스(엔티티, 배열, 개체 또는 null)

반환:

리소스의 배열 표현

반환 형식:

array

API 리소스의 구조를 정의하려면 하위 클래스에서 이 추상 메서드를 구현해야 합니다. 리소스 매개변수에는 변환되는 데이터가 포함됩니다. $resource 매개변수의 데이터에 액세스하여 API 응답에 포함하려는 필드가 포함된 배열을 반환합니다.

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class ProductTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'id'          => $resource['id'],
            'name'        => $resource['name'],
            'price'       => $resource['price'],
            'in_stock'    => $resource['stock_quantity'] > 0,
            'description' => $resource['description'],
        ];
    }
}
transform($resource = null)
매개변수:
  • $resource (mixed) – 변환할 리소스(엔티티, 배열, 개체 또는 null)

반환:

변환된 배열

반환 형식:

array

리소스 데이터로 toArray()을 호출하여 지정된 리소스를 배열로 변환합니다. $resourcenull인 경우 nulltoArray()에 전달합니다. 엔터티인 경우 먼저 배열 표현을 추출합니다. 그렇지 않으면 배열로 캐스팅합니다.

리소스는 $this->resource에도 저장되므로 include 메소드에서 액세스할 수 있습니다.

이 메서드는 필드 필터링을 자동으로 적용하고 쿼리 매개변수를 기반으로 포함합니다.

<?php

use App\Transformers\UserTransformer;

$user = model('UserModel')->find(1);

$transformer = new UserTransformer();

// Transform an entity
$result = $transformer->transform($user);

// Transform an array
$userData = ['id' => 1, 'name' => 'John Doe'];
$result   = $transformer->transform($userData);

// Use toArray() data
$result = $transformer->transform();
transformMany(array $resources)
매개변수:
  • $resources (array) – 변환할 리소스 배열

반환:

변환된 리소스 배열

반환 형식:

array

각 항목에 대해 transform()을 호출하여 리소스 컬렉션을 변환합니다. 필드 필터링 및 포함은 모든 항목에 일관되게 적용됩니다.

<?php

use App\Transformers\UserTransformer;

$users = model('UserModel')->findAll();

$transformer = new UserTransformer();
$results     = $transformer->transformMany($users);

// $results is an array of transformed user arrays
foreach ($results as $user) {
    // Each $user is the result of calling transform() on an individual user
}
getAllowedFields()
반환:

허용되는 필드 이름의 배열 또는 모든 필드를 허용하는 null

반환 형식:

array|null

fields 쿼리 매개변수를 통해 요청할 수 있는 필드를 제한하려면 이 메서드를 재정의하세요. toArray() 메서드의 모든 필드를 허용하려면 null (기본값)을 반환합니다. 허용된 필드의 화이트리스트를 생성하려면 필드 이름 배열을 반환합니다.

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class UserTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'id'         => $resource['id'],
            'name'       => $resource['name'],
            'email'      => $resource['email'],
            'created_at' => $resource['created_at'],
        ];
    }

    protected function getAllowedFields(): ?array
    {
        // Clients can only request id, name, and created_at
        // Attempting to request 'email' will throw an ApiException
        return ['id', 'name', 'created_at'];
    }
}
getAllowedIncludes()
반환:

허용된 포함 이름의 배열 또는 모든 포함을 허용하는 null

반환 형식:

array|null

include 쿼리 매개변수를 통해 포함될 수 있는 관련 리소스를 제한하려면 이 메서드를 재정의하세요. 해당 메서드가 있는 모든 포함을 허용하려면 null (기본값)을 반환합니다. 화이트리스트를 생성하려면 포함 이름의 배열을 반환합니다. 모든 포함을 비활성화하려면 빈 배열을 반환합니다.

<?php

namespace App\Transformers;

use CodeIgniter\API\BaseTransformer;

class UserTransformer extends BaseTransformer
{
    public function toArray(mixed $resource): array
    {
        return [
            'id'    => $resource['id'],
            'name'  => $resource['name'],
            'email' => $resource['email'],
        ];
    }

    protected function getAllowedIncludes(): ?array
    {
        // Only 'posts' can be included via ?include=posts
        // Attempting to include 'orders' will throw an ApiException
        return ['posts'];
    }

    protected function includePosts(): array
    {
        $posts = model('PostModel')->where('user_id', $this->resource['id'])->findAll();

        return (new PostTransformer())->transformMany($posts);
    }

    protected function includeOrders(): array
    {
        // This method exists but cannot be called via the API
        $orders = model('OrderModel')->where('user_id', $this->resource['id'])->findAll();

        return (new OrderTransformer())->transformMany($orders);
    }
}

예외 참조

class CodeIgniter\API\ApiException
static forInvalidFields(string $field)
매개변수:
  • $field (string) – 잘못된 필드 이름

반환:

ApiException 인스턴스

반환 형식:

ApiException

클라이언트가 허용된 필드 목록에 없는 fields 쿼리 매개변수를 통해 필드를 요청할 때 발생합니다.

static forInvalidIncludes(string $include)
매개변수:
  • $include (string) – 잘못된 포함 이름입니다.

반환:

ApiException 인스턴스

반환 형식:

ApiException

클라이언트가 허용된 포함 목록에 없는 include 쿼리 매개변수를 통해 포함을 요청할 때 발생합니다.

static forMissingInclude(string $include)
매개변수:
  • $include (string) – 누락된 포함 메소드 이름

반환:

ApiException 인스턴스

반환 형식:

ApiException

클라이언트가 include 쿼리 매개변수를 통해 포함을 요청했지만 해당 include*() 메서드가 변환기 클래스에 없을 때 발생합니다. 이 유효성 검사를 통해 요청된 모든 포함에 적절한 처리기 메서드가 정의되어 있는지 확인합니다.