Back-End

19 nov, 2014

Fractal V0.8.0, agora com Serializers

Publicidade

Uma nova versão do Fractal foi lançada, e ela é um pacote que visa a tornar mais fácil a vida dos desenvolvedores de API que lidam com output.

Num nível básico, ele atua como um typecast um array de dados, como array_map (), porém definido nas classes. No entanto, ele pode fazer muito mais. Por exemplo, ele pode ajudar a incluir outros recursos dentro da resposta com base na entrada do usuário, para que  /books?include=author,comments lhe dê exatamente o que você espera, sem precisar de códigos complexos sempre que for exibi-los.

Até a v0.8.0 – quando Jason Lewis se envolveu com uma série de pull requests -, a estrutura de dados sempre foi bem codificada. Você não poderia mudar a forma como a paginação se parecia, e eu estava usando um namespace data que as pessoas queriam remover. Serializers sempre estiveram na lista de tarefas, mas Jason entrou lá e colocou ordem nas coisas.

Então, eu vou fazer um repost da nova página de documentação que acabei de escrever.

Um Serializer estrutura seus dados transformados em determinadas maneiras. Existem muitas estruturas de saída para APIs e dois dos mais populares são HAL e JSON-API. Os dados de saída de Twitter e Facebook se diferem um do outro, e o Google faz isso de forma diferente também. Classes Serializer permitem alternar entre vários formatos de saída com efeito mínimo sobre seus Transformers.

Um uso muito básico do Fractal, como já foi visto em outras seções, ficará assim:

use Acme\Model\Book;
use Acme\Transformer\BookTransformer;
use League\Fractal\Manager;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\DataArraySerializer;

$manager = new Manager();
$manager->setSerializer(new DataArraySerializer());

// Some sort of ORM call
$book = Book::find(1);

// Make a resource out of the data and 
$resource = new Item($book, new BookTransformer(), 'book');

// Run all transformers
$manager->createData($resource)->toArray();

// Outputs: 
// [ 
//   'data' => [ 
//     'id' => 'Foo', 
//     'title' => 'Foo', 
//     'year' => 1991, 
//   ], 
// ];

O que é novo aqui é o $manager->setSerializer(new DataArraySerializer()); part. DataArraySerializer é o nome do serializer padrão no Fractal, mas existem mais.

DataArraySerializer

Este serializer não é para o gosto de todos porque acrescenta um namespace ‘data‘ para a saída:

// Item
[
    'data' => [
        'foo' => 'bar'
    ],
];

// Collection 
[
    'data' => [ 
         [ 
              'foo' => 'bar' 
         ] 
    ], 
];

Isso é útil porque permite espaço para metadados (como paginação) em ambos itens e coleções.

/ Item with Meta
[
    'data' => [
        'foo' => 'bar'
    ],
    'meta' => [
        ...
    ]
];

// Collection with Meta
[ 
    'data' => [
         [ 
              'foo' => 'bar'
         ] 
    ], 
    'meta' => [
         ... 
    ]
];

Isso se encaixa muito bem para os meta recursos e recursos incluídos, usando o namespace ‘data’. Isso significa que os metadados podem ser adicionados para os recursos incluídos também.

// Item with included resource using meta
[
    'data' => [
        'foo' => 'bar'
        'comments' => [
            'data' => [
                ...
            ],
            'meta' => [
                ...
            ]
        ]
    ],
];

ArraySerializer

Às vezes, as pessoas querem remover o namespace ‘data’, e isso pode ser feito usando o ArraySerializer, que é basicamente o mesmo que sem o namespace.

use League\Fractal\Serializer\ArraySerializer;
$manager->setSerializer(new ArraySerializer());
// Item
[
    'foo' => 'bar'
];

// Collection 
[ 
     [ 
          'foo' => 'bar' 
     ]
];

Metadados são excelentes para itens, mas acabam ficando um pouco confusos para coleções:

// Item with Meta
[
    'foo' => 'bar'
    'meta' => [
        ...
    ]
];

// Collection with Meta 
[ 
      [ 
           'foo' => 'bar' 
      ]
      'meta' => [ 
          ... 
      ]
];

Acrescentar uma chave nomeada para algo que é apenas uma lista deixa o JSON confuso:

{"0":{"foo":"bar"},"meta":{}}

Esse “0” está lá porque você não pode misturar as chaves indexadas e as não indexadas sem o JSON decidir torná-lo uma estrutura (objeto) em vez de uma lista (array).

É por isso que o ArraySerialzier não é recomendado, mas se você não estiver usando metadados … então siga em frente.

JsonApiSerializer

Este é um trabalho de representação do padrão JSON-API em progresso. Ele é incluído como parcialmente funcionando, mas tem há trabalho para ser feito.

São poucas as diferenças com o JsonApiSerializer. A primeira é que ele usa “side-loading” para incluir outros recursos relacionados, que é diferente da abordagem de “embedding”, que é usada para incluir recursos de outros dois serializers.

A segunda é que ele requer um recurso fundamental, o que não acontece com os outros dois.

use League\Fractal\Serializer\JsonApiSerializer;
$manager->setSerializer(new JsonApiSerializer());

// Important, notice the Resource Key in the third parameter:
$resource = new Item($book, new GenericBookTransformer(), 'book'); 
$resource = new Collection($books, new GenericBookTransformer(), 'books');

Aquela chave de recurso é usada para dar nomear um namespace:

// Item
[
    'book' => [
        'foo' => 'bar'
    ],
];

// Collection
[ 
     'books' => [
          [ 
              'foo' => 'bar' 
          ] 
     ], 
];

Assim como DataArraySerializer, isso funciona muito bem para metadados:

// Item with Meta
[
    'book' => [
        'foo' => 'bar'
    ],
    'meta' => [
        ...
    ]
];

// Collection with Meta
[ 
     'books' => [
          [ 
              'foo' => 'bar' 
          ] 
     ],
     'meta' => [ 
         ... 
     ] 
];

O acréscimo de um recurso a uma resposta ao item ficaria assim:

// Item with Meta
[
    'book' => [
        'foo' => 'bar'
    ],
    'linked' => [
        'author' => [
            [
                'name' => 'Dave'
            ]
        ]
    ]
];

Serializers Personalizados

Você pode fazer seus próprios Serializers implementando o SerializerAbstract.

use Acme\Serializer\CustomSerializer;
$manager->setSerializer(new CustomSerializer());

A estrutura de serializers mudará em algum ponto para permitir que os itens e as coleções sejam tratados de maneira diferente e para melhorar a lógica side-loading. Fique de olho no registro de alterações, mas não tenha medo de fazer um.

Ainda existe muito trabalho para ser feito com serializers, mas eles já são bastante úteis. Eu adicionei algumas características que eu precisava para um projeto de um cliente, mas eu não posso trabalhar em outros até que tenha cumprido esse prazo.

***

Artigo traduzido pela Redação iMasters com autorização do autor. Publicado originalmente em  http://philsturgeon.uk/blog/2014/05/fractal-v080-now-with-serializers