neomerx / json-api

Framework agnostic JSON API (jsonapi.org) implementation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question: Make single Schema Class and other things

mtangoo opened this issue · comments

Hi,
am currently in search of right JSONApi library to use. I was reading your implementation and I found it using few classes (Model, Schema and Encoder -- did I miss anything else). Now looking at schema it needs ID and Attributes. Now I use Laravel's Eloquent models for data in non-Laravel homegrown framework that am trying to add JSONAPI ability. Now I have questions:

  1. Is there a way I can tell the library about how to fetch attributes and id apart from current way (I'm thinking of making schema class that gets Model in its c'tor and returns the attributes and id but wanted to know if there is easier way)
  2. Does the library provide a class for taking data from JSONAPI request and create an Object of that class from data?

Tanks for the library and time.

Hi,

The library is framework agnostic and do not rely on any specific Model classes (do not require). You can view Schema as an adapter for models you use (Eloquent, Doctrine, plain classes or else). As you can see in wiki you can use any ORM you like.

I'm thinking of making schema class that gets Model in its c'tor and returns the attributes and id but wanted to know if there is easier way)

I think the way it works now is easier. You create Schemes each of them can 'transform' your models to format which Encoder understands. The library would reuse Schema instances (they do not store any data from models) which is way more efficient than creating 1 schema for every 1 model.

Does the library provide a class for taking data from JSONAPI request and create an Object of that class from data?

The library do not provide parser for JSON API documents. The reason is that IMHO it cannot be developed in generic and efficient way. For example

  • should it parse meta and links? For CRUD it's not necessary but for 'generic' parser it should be done
  • how to deal with polymorphic data? For typical usage it's not needed though for 'generic' solution it should be done. And even if added it would be very opinionated.
  • what parser should do with attributes/meta/links in relationships? For create and update only type + id is needed. So parsing the rest would slow the parser.

I feel I have answered the question and I don't have any feedback from you. I'm closing the question. If you have any further questions please don't hesitate to ask.

Thank you a lot. For sure you ave answered them with details. Sorry for the feedback, I got caught with some other thing. However one thing is still not clear in your answer:

I think the way it works now is easier. You create Schemes each of them can 'transform' your models to format which Encoder understands. The library would reuse Schema instances (they do not store any data from models) which is way more efficient than creating 1 schema for every 1 model.

If my model have uniform interface they implement that provides all information schema needs, shouldn't I have a single schema that deals with it all? Something like

interface IModel
{
    public function getAttributes();
    public function getId();
}

Then I will have just a single Schema with something like

class AuthorSchema extends SchemaProvider
{
    protected $resourceType = 'people';

    public function getId($model)
    {
        /** @var Author $author */
        return $author->getId();
    }

    public function getAttributes($author)
    {
        /** @var Author $author */
       return $author->getAttributes();
    }
}

Then with every model I just Plugin the same Schema. What's your opinion on that?

Sure you can do that and have one Schema for all models. Though $resourceType must have different values and there are usually requirements that differ from schema to schema. They 'might'/'might not' have links/meta/paging info/relationships/defaut include paths/etc so in general case it's better to support multiple schemes.
If you feel you can have 1 schema for all I would recommend something like

abstract class BaseSchema  extends SchemaProvider
{
 ...
}

class AuthorSchema extends BaseSchema
{
    protected $resourceType = 'people';
}

I see your point. I have not looked deep, but my impression was the support for all those (links/meta/paging info/relationships/etc) is similar to what I have read in getId() and getAttributes(). Is that so?

As of resourceType, why is it hard-corded instead of flexible function like getId() is? IMHO it kill flexibility of Schema that is already there in other functions.

As you can see they are protected and cannot be used outside of the class. They are not used directly in the class as well (only via getters). You can override the following methods and be good (default implemnetation below)

    /**
     * @inheritdoc
     */
    public function getResourceType()
    {
        return $this->resourceType;
    }

    /**
     * @inheritdoc
     */
    public function getSelfSubUrl($resource = null)
    {
        return $resource === null ? $this->selfSubUrl : $this->selfSubUrl . '/' . $this->getId($resource);
    }

the reason is that defining 1 property is easier than 2 methods.

overriding them is better method. I didn't knew that method exists. Let me work with information I have. I will be coming back for questions in issues (unless there is other specific place).

I appreciate your time and help. Thank you!

This library is built on interfaces. It means you can replace any part of the lib with your interface implementation. You don't like default SchemaProvider? No probs. You can implement SchemaProviderInterface the way you like and it will work absolutely fine.

Is it possible to pass instance of schema instead of string of the class name? I tried that and got
Catchable fatal error: Argument 1 passed to Neomerx\JsonApi\Schema\SchemaProvider::__construct() must be an instance of Neomerx\JsonApi\Contracts\Schema\SchemaFactoryInterface, none given
I ask that because I want to configure some internal properties of my schema before sending it to encoder.

@mtangoo you can pass Closure. Have a look at sample in wiki