Yin
The efficient and elegant JSON:API 1.1 server library for PHP
Install / Use
/learn @woohoolabs/YinREADME
Woohoo Labs. Yin
[![Latest Version on Packagist][ico-version]][link-version] ![Software License][ico-license] [![Build Status][ico-build]][link-build] [![Coverage Status][ico-coverage]][link-coverage] [![Quality Score][ico-code-quality]][link-code-quality] [![Total Downloads][ico-downloads]][link-downloads] [![Gitter][ico-support]][link-support]
Woohoo Labs. Yin is a PHP framework which helps you to build beautifully crafted JSON:APIs.
Table of Contents
- Introduction
- Install
- Basic Usage
- Advanced Usage
- Examples
- Integrations
- Versioning
- Change Log
- Testing
- Contributing
- Support
- Credits
- License
Introduction
JSON:API specification reached 1.0 on 29th May 2015 and we also believe it is a big day for RESTful APIs as this specification can help you make APIs more robust and future-proof. Woohoo Labs. Yin (named after Yin-Yang) was born to bring efficiency and elegance to your JSON:API servers, while Woohoo Labs. Yang is its client-side counterpart.
Features
- 100% PSR-7 compatibility
- 99% JSON:API 1.1 compatibility (approximately)
- Developed for efficiency and ease of use
- Extensive documentation and examples
- Provides Documents and Transformers to fetch resources
- Provides Hydrators to create and update resources
- Additional middleware for the easier kickstart and debugging
Why Yin?
Complete JSON:API framework
Woohoo Labs. Yin is a framework-agnostic library which supports the vast majority of the JSON:API 1.1 specification: it provides various capabilities including content negotiation, error handling and pagination, as well as fetching, creation, updating and deleting resources. Although Yin consists of many loosely coupled packages and classes which can be used separately, the framework is most powerful when used in its entirety.
Efficiency
We designed Yin to be as efficient as possible. That's why attributes and relationships are transformed only and if only they are requested. This feature is extremely advantageous when there are a lot of resources to transform or a rarely required transformation is very expensive. Furthermore, as transformers are stateless, the overhead of having a separate model object for each resource is avoided. Additionally, due to statelessness, the overall library works really well with dependency injection.
Supplementary middleware
There is some additional middleware for Woohoo Labs. Yin you might find useful. It can facilitate various tasks like error handling (via transformation of exceptions into JSON:API error responses), dispatching JSON:API-aware controllers or debugging (via syntax checking and validation of requests and responses).
Install
The only thing you need before getting started is Composer.
Install a PSR-7 implementation:
Because Yin requires a PSR-7 implementation (a package which provides the psr/http-message-implementation virtual
package), you must install one first. You may use Laminas Diactoros or
any other library of your preference:
$ composer require laminas/laminas-diactoros
Install Yin:
To install the latest version of this library, run the command below:
$ composer require woohoolabs/yin
Note: The tests and examples won't be downloaded by default. You have to use
composer require woohoolabs/yin --prefer-sourceor clone the repository if you need them.
The latest version of Yin requires PHP 7.1 at least but you can use Yin 2.0.6 for PHP 7.0.
Install the optional dependencies:
If you want to take advantage of request/response validation then you have to also ask for the following dependencies:
$ composer require justinrainbow/json-schema
$ composer require seld/jsonlint
Basic Usage
When using Woohoo Labs. Yin, you will create:
- Documents and resources in order to map domain objects to JSON:API responses
- Hydrators in order to transform resources in a POST or PATCH request to domain objects
Furthermore, a JsonApi class will be responsible for the instrumentation, while a PSR-7 compatible
JsonApiRequest class provides functionalities you commonly need.
Documents
The following sections will guide you through creating documents for successful responses and creating or building error documents.
Documents for successful responses
For successful requests, you must return information about one or more resources. Woohoo Labs. Yin provides multiple abstract classes that help you to create your own documents for different use cases:
AbstractSuccessfulDocument: A generic base document for successful responsesAbstractSimpleResourceDocument: A base class for documents about a single, very simple top-level resourceAbstractSingleResourceDocument: A base class for documents about a single, more complex top-level resourceAbstractCollectionDocument: A base class for documents about a collection of top-level resources
As the AbstractSuccessfulDocument is only useful for special use-cases (e.g. when a document can contain resources
of multiple types), we will not cover it here.
The difference between the AbstractSimpleResourceDocument and the AbstractSingleResourceDocument classes is that
the first one doesn't need a resource object. For this reason, it is preferable to use
the former for only really simple domain objects (like messages), while the latter works better for more complex domain
objects (like users or addresses).
Let's first have a quick look at the AbstractSimpleResourceDocument: it has a getResource() abstract method which
needs to be implemented when you extend this class. The getResource() method returns the whole transformed resource as
an array including the type, id, attributes, and relationships like below:
protected function getResource(): array
{
return [
"type" => "<type>",
"id" => "<ID>",
"attributes" => [
"key" => "value",
],
];
}
Please note that
AbstractSimpleResourceDocumentdoesn't support some features out-of-the-box like sparse fieldsets, automatic inclusion of related resources etc. That's why this document type should only be considered as a quick-and-dirty solution, and generally you should choose another, more advanced document type introduced below in the majority of the use cases.
AbstractSingleResourceDocument and AbstractCollectionDocument both need a resource object in order to work,
which is a concept introduced in the following sections. For now, it is enough to know that one must be passed for the documents
during instantiation. This means that a minimal constructor of your documents should look like this:
public function __construct(MyResource $resource)
{
parent::__construct($resource);
}
You can of course provide other dependencies for your constructor or completely omit it if you don't need it.
When you extend either AbstractSingleResourceDocument or AbstractCollectionDocument, they both require
you to implement the following methods:
/**
* Provides information about the "jsonapi" member of the current document.
*
* The method returns a new JsonApiObject object if this member should be present or null
* if it should be omitted from the response.
*/
public function getJsonApi(): ?JsonApiObject
{
return new JsonApiObject("1.1");
}
The description says it very clear: if you want a jsonapi member in your response, then create a new JsonApiObject.
Its constructor expects the JSON:API version number and an optional meta object (as an array).
/**
* Provides information about the "meta" member of the current document.
*
* The method returns an array of non-standard meta information about the document. If
* this array is empty, the member won't appear in the response.
*/
public function getMeta(): array
{
return [
"page" => [
"offset" => $this->object->getOffset(),
"limit" => $this->object->getLimit(),
"total" => $this->object->getCount(),
]
];
}
Documents may also have a "meta" member which can contain any non-standard information. The example above adds information a
