이제 서버 프로그래머의 주요 업무는 더 이상 템플릿을 설정하는 것이 아니라 JSON 기반 API 인터페이스를 작성하는 것입니다. 불행하게도 모든 사람은 매우 다른 스타일의 인터페이스를 가지고 있어 시스템 통합에 불필요한 통신 비용이 많이 발생합니다. 비슷한 문제가 있는 경우 JSON 기반 API 구축을 위한 표준인 JSONAPI에 주의를 기울이는 것이 좋습니다. 간단한 API 인터페이스는 대략 다음과 같습니다:
JSONAPI
간단한 설명: 루트 노드의 데이터는 기본 개체의 콘텐츠를 배치하는 데 사용됩니다. 여기서 유형과 ID는 필수 필드이며 유형과 기본 개체의 식별, 기타 모든 단순 속성은 기본 개체에 일대일, 일대다 및 기타 관련 개체가 있는 경우 관계에 배치됩니다. type 및 id 필드를 통해 관련 객체의 실제 콘텐츠가 루트 노드에 포함됩니다.
JSONAPI를 사용하면 데이터 구문 분석 프로세스가 표준화되어 불필요한 통신 비용이 절약됩니다. 그러나 JSONAPI 데이터를 수동으로 구성하는 것은 여전히 매우 번거로운 작업입니다. 다행히 Fractal을 사용하면 구현 프로세스가 상대적으로 자동화될 수 있습니다. 위의 예를 Fractal로 구현하면 아마도 다음과 같을 것입니다. 내가 가장 좋아하는 PHP 툴킷을 선택하라고 하면 Fractal이 목록에 있어야 합니다. 이 툴킷은 구현 세부 정보를 숨기고 사용자가 JSONAPI 프로토콜을 전혀 몰라도 시작할 수 있도록 해줍니다. 하지만 자신의 프로젝트에서 Fractal을 직접 사용하는 대신 Fractalistic을 사용해 볼 수 있습니다. Fractal을 캡슐화하여 사용하기 더 쉽게 만듭니다.
<?php use League\Fractal\Manager; use League\Fractal\Resource\Collection; $articles = [ [ 'id' => 1, 'title' => 'JSON API paints my bikeshed!', 'body' => 'The shortest article. Ever.', 'author' => [ 'id' => 42, 'name' => 'John', ], ], ]; $manager = new Manager(); $resource = new Collection($articles, new ArticleTransformer()); $manager->parseIncludes('author'); $manager->createData($resource)->toArray(); ?>
PHP를 Naked로 작성하는 경우 기본적으로 Fractalistic은 최선의 선택이지만 일부 풀 스택 프레임워크를 사용하는 경우 Fractalistic은 프레임워크 자체의 기존 기능과 더 완벽하게 통합될 수 없기 때문에 충분히 우아하지 않을 수 있습니다. 이를 기반으로 프레임워크와 완벽하게 통합될 수 있는 JsonApiSerializer를 구현했습니다. 코드는 다음과 같습니다.
<?php Fractal::create() ->collection($articles) ->transformWith(new ArticleTransformer()) ->includeAuthor() ->toArray(); ?>
해당 Resource는 반환 값을 제외하면 기본적으로 이전과 동일합니다. 변경되었습니다:
<?php namespace App\Http\Serializers; use Illuminate\Http\Resources\MissingValue; use Illuminate\Http\Resources\Json\Resource; use Illuminate\Http\Resources\Json\ResourceCollection; use Illuminate\Pagination\AbstractPaginator; class JsonApiSerializer implements \JsonSerializable { protected $resource; protected $resourceValue; protected $data = []; protected static $included = []; public function __construct($resource, $resourceValue) { $this->resource = $resource; $this->resourceValue = $resourceValue; } public function jsonSerialize() { foreach ($this->resourceValue as $key => $value) { if ($value instanceof Resource) { $this->serializeResource($key, $value); } else { $this->serializeNonResource($key, $value); } } if (!$this->isRootResource()) { return $this->data; } $result = [ 'data' => $this->data, ]; if (static::$included) { $result['included'] = static::$included; } if (!$this->resource->resource instanceof AbstractPaginator) { return $result; } $paginated = $this->resource->resource->toArray(); $result['links'] = $this->links($paginated); $result['meta'] = $this->meta($paginated); return $result; } protected function serializeResource($key, $value, $type = null) { if ($type === null) { $type = $key; } if ($value->resource instanceof MissingValue) { return; } if ($value instanceof ResourceCollection) { foreach ($value as $k => $v) { $this->serializeResource($k, $v, $type); } } elseif (is_string($type)) { $included = $value->resolve(); $data = [ 'type' => $included['type'], 'id' => $included['id'], ]; if (is_int($key)) { $this->data['relationships'][$type]['data'][] = $data; } else { $this->data['relationships'][$type]['data'] = $data; } static::$included[] = $included; } else { $this->data[] = $value->resolve(); } } protected function serializeNonResource($key, $value) { switch ($key) { case 'id': $value = (string)$value; case 'type': case 'links': $this->data[$key] = $value; break; default: $this->data['attributes'][$key] = $value; } } protected function links($paginated) { return [ 'first' => $paginated['first_page_url'] ?? null, 'last' => $paginated['last_page_url'] ?? null, 'prev' => $paginated['prev_page_url'] ?? null, 'next' => $paginated['next_page_url'] ?? null, ]; } protected function meta($paginated) { return [ 'current_page' => $paginated['current_page'] ?? null, 'from' => $paginated['from'] ?? null, 'last_page' => $paginated['last_page'] ?? null, 'per_page' => $paginated['per_page'] ?? null, 'to' => $paginated['to'] ?? null, 'total' => $paginated['total'] ?? null, ]; } protected function isRootResource() { return isset($this->resource->isRoot) && $this->resource->isRoot; } } ?>
의 해당 컨트롤러는 루트를 식별하기 위해 isRoot 속성이 추가된다는 점을 제외하면 원본과 유사합니다.
<?php namespace App\Http\Resources; use App\Article; use Illuminate\Http\Resources\Json\Resource; use App\Http\Serializers\JsonApiSerializer; class ArticleResource extends Resource { public function toArray($request) { $value = [ 'type' => 'articles', 'id' => $this->id, 'name' => $this->name, 'author' => $this->whenLoaded('author'), ]; return new JsonApiSerializer($this, $value); } } ?>
전체 프로세스는 Laravel의 아키텍처에 너무 많이 개입하지 않습니다. 현재 Laravel이 JSONAPI를 구현하고 있다고 할 수 있습니다. 관심이 있다면 JsonApiSerializer 구현을 연구해 볼 수 있습니다. 코드가 100줄이 넘지만 구현하는 데 많은 노력을 기울일 수 있습니다. 모든 단계가 힘든 일이라고 합니다.
관련 권장 사항:
JSON 형식 배열을 Excel 테이블로 다운로드하는 JavaScript의 자세한 예
위 내용은 PHP에서 JSONAPI 적용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!