woohoolabs / yang

The efficient and elegant, PSR-7 compliant JSON:API 1.1 client library for PHP

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to share common schemas/resources/etc between yin and yang

Doqnach opened this issue · comments

I am currently writing a JSON:API server implementation which will also have clients that will consume the API. The server is Symfony 4 using woohoolabs/yin. It contains a bunch of schemas, documents, resources, hydrators, etc.

I was looking in how to include these in a client-library, but everything extends stuff from the Woohoolabs\Yin namespace, whereas on the client side you are working from the Woohoolabs\Yang namespace.

Yang doesn't seem to share a base with Yin that would enable me to reuse code. What is the preferred way here? Write a totally separate client library, resulting in a high amount of duplicate code?

Hi @Doqnach ,

Yes, Yin & Yang are completely separated from each other.

The first reason I didn't want to share schema between the two libraries is that coupling the server and client implementation goes against the purpose of having an API - where the aim would be that the server and client could evolve independently. I think it's very difficult to achieve if you have a single underlying schema for both the server and client. Maybe you could separate the schema to an individual package and use semantic versioning when using it on the server and client, but I am not sure it works well on the long run. If you have any experience with sharing code between server and client, I am happy to hear it!

Furthermore, my aim with Yang was to:

  • make it possible to query every detail of the response by using the JsonApiResponse class
  • but in the same time, make it very easy to retrieve all attributes and relationships of the response by using the ClassDocumentHydrator

And I think it's enough to provide by a client library. In my opinion, if you need a somewhat useful schema on the client-side, you should map the response manually to domain object(s) of yours. But Yang can't do this automatically (and I am not into magical things - like the things Doctrine does for example).

I am on this viewpoint even more, because normally, the client-side doesn't (and shouldn't) contain much logic (except for some presentational one), and that's why usually the API response is only consumed in template code (e.g. Twig in PHP) where type safety - that a schema could offer - can't be made use of.

At least these are my experiences. I know that there are way different use-cases than mine, but my requirements against Yang were based on these assumptions when I started to build it.

I am curious about your thoughts!

the aim would be that the server and client could evolve independently

But... if the server changes the 'interface' (e.g. adds a field to a response), the client needs to follow? Now that means maintaining two separate but almost identical pieces of code.

I would then provide the hydrator in a (composer) client library that converts the JsonApiResponse body to a domain object at the "client" side on a 'GET' request to the server, which is the same process as converting the JsonApiRequest body to the exact same domain object on a 'POST' request on the "server" side coming from that "client".
In both cases the body is a string (stream) and the domain objects are the same, so conversion would be done in an identical way.

In this case this is backend-to-backend communication, where one backend is a "client" (generating a new resource) and requesting the other backend ("server") to persist it (save it in a datastore).

So right now I would have to make both backend services implement yin.