REST API with JSON:API Standard
Tags: php, rest, api, tutorial
Published: 2020-07-06 14:33:21

If you are looking for another article about how to REST API, I've good news for you. You found it!

Here is short list of topics:
1. [There will be a short prolog, why I'm doing this](#long-story-short)
2. [A little talk about JSON:API Standard](#what-is-jsonapi-standard-and-why-you-should-use-it)
3. [What I offer to you, to make you life easier](#so-what-exactly-im-offering-to-you)

# Long story short

As every web developer I need API with which I can communicate from FE client or another service. So as most of developers I was searching for some solution, something like BRB (Big Red Button). You know, the solution to every problem of the world, just press the button and everything happend as you wish. But it didn't happend. I did not found BRB solution, so I begin with something on my own.

# What is JSON:API Standard and why you should use it

I love these titles, it's some kind of cliché. But to the point. There is bunch of people working on some standardised format, to make world of REST API's, using json, great again. The main goal is to stop dev-teams arguing about document format and this is great idea. If you look at APIs around the internet, there is so much different formats. Every dev-person creates their own, at least, once in their life.

So why tho? Because if we all use some standards, there gonna be a lot of awesome tools doing boring work instead of us. The proof is PSR, look how much awesome libraries exist implementing those standards.

# So what exactly I'm offering to you?

I suppose that most of us know about [Doctrine project](https://www.doctrine-project.org/), hope that some of us know [SlimPHP](http://www.slimframework.com/) framework and if you are nerd like me, you definitly love [PSR standards](https://www.php-fig.org/psr/) and other helpfull iniciative of comunity to make our PHP usefull and beatiful. 

If it's all true, you definitely have some dev stack with Doctrine. So you have something like this in your codebase:

```php

/**
 * Class Location
 *
 * @package App\Model\Entity\JSprit
 * @ORM\Entity(repositoryClass=LocationRepository::class)
 * @ORM\Table(schema="jsprit")
 * @ORM\HasLifeCycleCallbacks
 */
class Location extends Entity
{
    use Keyable;

    /**
     * @var double
     * @ORM\Column(type="float")
     */
    private float $lon;

    /**
     * @var double
     * @ORM\Column(type="float")
     */
    private float $lat;

    /**
     * @var string|null
     * @ORM\Column(type="string", nullable=true)
     */
    private ?string $name = null;
...
```
Standard entity. Some propreties with standard ORM annotations. It's easy and smart. So next, at most cases, you want expose those entities to the world, right? So what about this:

```php

/**
 * Class Location
 *
 * @package App\Model\Entity\JSprit
 * @ORM\Entity(repositoryClass=LocationRepository::class)
 * @ORM\Table(schema="jsprit")
 * @ORM\HasLifeCycleCallbacks
 * @API\Resource("locations")      <<< just add another annotation
 */
class Location extends Entity
{
    use Keyable;

    /**
     * @var double
     * @ORM\Column(type="float")
     * @API\Attribute                                <<< and here
     */
    private float $lon;

    /**
     * @var double
     * @ORM\Column(type="float")
     * @API\Attribute                                 <<< and here
     */
    private float $lat;
```
That's it! Now we created [Resource](https://jsonapi.org/format/#document-resource-objects) with two [attributes](https://jsonapi.org/format/#document-resource-object-attributes), easy right? 

So how exactly you create [this beatiful document](https://jsonapi.org/format/#document-compound-documents)? Now, when you have annotated entities, therefore resources, we can create compound document very easy.

```php
$entity = $this->repository->find($id);
$response->withJson(
    DocumentBuilder::create($this->metadataRepository, $this->createUriParser($request))
    ->setData($entity)
    ->build()
);
```
Beeem! You have JSON:API Standard reponse in JSON with your entity data.
```json
{
    "jsonapi": {
        "version": "1.0"
    },
    "data": {
        "type": "locations",
        "id": "161814",
        "attributes": {
            "lon": 17.6948149843,
            "lat": 50.0957670457,
            "name": "Location 123"
        },
        "relationships": {
            "orders": {
                "data": [],
                "links": {
                    "self": "http:\/\/example.com\/api\/\/locations\/161814\/relationships\/orders",
                    "related": "http:\/\/example.com\/api\/\/locations\/161814\/orders"
                },
                "meta": {
                    "total": 0
                }
            }
        },
        "links": {
            "self": "http:\/\/example.com\/api\/\/locations\/161814"
        }
    },
    "links": {
        "self": "http:\/\/example.com\/api\/\/locations\/161814"
    }
}
```



### **All you need to do is download this library** https://gitlab.com/bednic/json-api



There is so much more of course. If you don't like annotations there is solution for you with schema-driven metadata. Just look to [documentation](https://gitlab.com/bednic/json-api/-/wikis/home#schema).

But wait there is more. You don't need use Doctrine ORM at all!

And as a bonus in near future, this library will generate The [OpenAPI Specification (OAS)](https://swagger.io/specification/) for you. Stay tuned!


If you have read this far, I'm very grateful and hope this will help you make JSON API's quicker and easier.