English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Analisi approfondita dell'applicazione di JSONAPI in PHP

Ora, il lavoro principale del programmatore del lato server non è più quello di adattare modelli, ma di scrivere interfacce API basate su JSON. Purtroppo, lo stile di scrittura delle interfacce API è spesso diverso, il che introduce molti costi di comunicazione inutili per l'integrazione del sistema. Se hai problemi simili, potrebbe essere utile prestare attenzione a JSONAPI, che è uno standard di norma per costruire API basate su JSON. Un'interfaccia API semplice potrebbe apparire così:

JSONAPI

Spiegazione semplice: il nodo radice 'data' viene utilizzato per posizionare il contenuto dell'oggetto principale, tra cui i campi 'type' e 'id' sono obbligatori per rappresentare il tipo e l'identificatore dell'oggetto principale. Altri attributi semplici vengono messi in 'attributes'. Se l'oggetto principale ha oggetti associati uno-a-uno o uno-a-molti, vengono messi in 'relationships', ma tramite i campi 'type' e 'id' viene messo solo un link, il contenuto reale degli oggetti associati viene messo nel nodo radice 'included'.

Con l'uso di JSONAPI, il processo di解析 dati diventa standardizzato, riducendo i costi di comunicazione inutili. Tuttavia, costruire manualmente dati JSONAPI può essere complicato, fortunatamente, l'uso di Fractal può rendere il processo di implementazione relativamente automatizzato. Esempio di implementazione con Fractal potrebbe essere qualcosa del genere:

<?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();
?>

Se mi dovessi scegliere il pacchetto PHP preferito, Fractal sarebbe sicuramente tra i migliori, poiché nasconde i dettagli di implementazione, permettendo agli utenti di iniziare a usarlo senza dover conoscere il protocollo JSONAPI. Tuttavia, se vuoi utilizzarlo nel tuo progetto, rispetto all'uso diretto di Fractal, puoi provare Fractalistic, che lo impacchetta in modo da renderlo più facile da usare:

<?php
Fractal::create();
  ->collection($articles);
  ->transformWith(new ArticleTransformer());
  ->includeAuthor();
  ->toArray();
?>

Se stai scrivendo PHP in modo puro, Fractalistic è praticamente la scelta migliore, ma se stai utilizzando alcuni framework full-stack, Fractalistic potrebbe non essere sufficientemente elegante, poiché non riesce a integrarsi perfettamente con le funzionalità esistenti del framework stesso. Prendiamo Laravel come esempio, che ha già una funzione di risorse API integrata, sulla quale ho implementato JsonApiSerializer, integrandosi perfettamente con il framework, il codice è il seguente:

<?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) {
      se ($value instanceof Resource) {
        $this->serializeResource($key, $value);
      } else {
        $this->serializeNonResource($key, $value);
      }
    }
    se (!$this->isRootResource()) {
      return $this->data;
    }
    $result = [
      'data' => $this->data,
    ];
    se (static::$included) {
      $result['included'] = static::$included;
    }
    se (!$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)
  {
    se ($type === null) {
      $type = $key;
    }
    se ($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();
    }
  }
  funzione protetta 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;
    }
  }
  funzione protetta 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,
    ];
  }
  funzione protetta 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;
  }
}
?>

Il Resource corrispondente è基本上还是和以前一样,只是返回值做了一些修改:

<?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);
  }
}
?>

Il Controller corrispondente è quasi uguale al precedente, ma è stato aggiunto un attributo isRoot per riconoscere la radice:

<?php
namespace App\Http\Controllers;
use App\Article;
use App\Http\Resources\ArticleResource;
class ArticleController extends Controller
{
  protected $article;
  public function __construct(Article $article)
  {
    $this->article = $article;
  }
  public function show($id)
  {
    $article = $this->article->with('author')->findOrFail($id);
    $resource = new ArticleResource($article);
    $resource->isRoot = true;
    return $resource;
  }
}
?>

Il processo non ha invaso troppo l'architettura di Laravel, può essere considerata la soluzione ottimale per implementare JSONAPI in Laravel al momento. Chi è interessato può esplorare l'implementazione di JsonApiSerializer, anche se ha solo una centinaia di righe di codice, ho speso molto sforzo per realizzarlo, è vero che ogni riga è stata fatta con fatica.

Sommario

Come è stato descritto sopra, l'autore ha introdotto l'applicazione di JSONAPI in PHP, sperando che sia utile a tutti. Se avete qualsiasi domanda, lasciate un messaggio, l'autore risponderà tempestivamente!

Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, il copyright è dell'autore originale, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.

Ti potrebbe interessare