PHP JSON API implementation (server side)

v1.2.3 2018-12-16 09:45 UTC


Making JSON API implementation (server side) easiest for you


composer require hackerboy/json-api

Run examples:

  • Example code: /example/index.php
  • Guide to set up /examples/index.php to see some examples of uses.
git clone https://github.com/hackerboydotcom/json-api ./hackerboy-json-api;
cd hackerboy-json-api;
composer install --dev;

Then config your localhost nginx/apache to access [LOCALHOST_PATH]/examples/index.php

Table of Contents

How to use?

Create your resource schema

For example, I'm gonna talk in a Laravel project context. Firstly, let's create a resource file: /app/Http/JsonApiResources/UserResource.php

namespace App\Http\JsonApiResources;
use HackerBoy\JsonApi\Abstracts\Resource;

class UserResource extends Resource {

    protected $type = 'users';

    public function getId($user)
        return $user->id;

    public function getAttributes($user)
        return [
            'name' => $user->name,
            'email' => $user->email

    * Meta is optional
    public function getMeta($user)
        return [
            'meta-is-optional' => $user->some_value

Configuration and mapping your resources

Now we can easily generate a JSON API document object like this:

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

use HackerBoy\JsonApi\Document;

class UserController extends Controller {
    public function index()
        // User to return
        $user = \App\User::find(1);
        $users = \App\User::take(10)->get();
        // Config and mapping
        $config = [
            'resource_map' => [
                \App\User::class => \App\Http\JsonApiResources\UserResource::class
                // Map your other model => resource
            'api_url' => 'http://example.com',
            'auto_set_links' => true, // Enable this will automatically add links to your document according to JSON API standard
        // Let's test it
        $document = new Document($config);
        $document->setData($user) // or set data as a collection by using ->setData($users)
                  ->setMeta(['key' => 'value']);
        return response()->json($document)->header('Content-Type', 'application/vnd.api+json');

Document set and add methods

The difference between "set methods" and "add methods" are is: "Set methods" will override the data while "add methods" will append to data.

Available "set" methods from $document object are:

  • setData($resourceOrCollection, $type = 'resource') // Default $type = 'resource', in case you need to return data as relationship object, change $type to 'relationship'
  • setIncluded($resourceOrCollection)
  • setErrors($errors) // Array or HackerBoy\JsonApi\Elements\Error object - single error or multiple errors data will both work for this method
  • setLinks($links) // Array of link data or HackerBoy\JsonApi\Elements\Links object
  • setMeta($meta) // Array of meta data or HackerBoy\JsonApi\Elements\Meta object

Available "add" methods from $document object are:

  • addIncluded($resourceOrCollection)
  • addErrors($errors) // Array or HackerBoy\JsonApi\Elements\Error object - single error or multiple errors data will both work for this method
  • addLinks($links) // Array of link data or HackerBoy\JsonApi\Elements\Links object
  • addMeta($meta) // Array of meta data or HackerBoy\JsonApi\Elements\Meta object



$document->setData([$post1, $post2]) // or ->setData($post) will also work
    ->setIncluded([$comment1, $comment2])
            'meta-key' => 'meta-value',
            'meta-key-2' => 'value 2'
            'first' => $document->getUrl('first-link'),
            'last' => $document->getUrl('last-link'),
            'prev' => $document->getUrl('prev-link'),
            'next' => $document->getUrl('last-link'),

Implement relationships

Simply return an array in getRelationships() method


namespace HackerBoy\JsonApi\Examples\Resources;

use HackerBoy\JsonApi\Abstracts\Resource;

class PostResource extends Resource {

    protected $type = 'posts';

    public function getId($post)
        return $post->id;

    public function getAttributes($post)
        return [
            'title' => $post->title,
            'content' => $post->content

    public function getRelationships($post)
        $relationships = [
            'author' => $post->author, // Post has relationship with author

            // If post has comments, return a collection
            // Not? Return a blank array (implement empty to-many relationship)
            'comments' => $post->comments ? $post->comments : []

        return $relationships;

Set data as relationships

Second param allows you to set data as relationship (for request like: /api/posts/1/relationships/comments)


// Set data as relationship
$document->setData($resourceOrCollection, 'relationship');

toArray() and toJson() methods

New methods in v1.1. Available for document, elements and resources

$data = $document->toArray();
$json = $document->toJson();

Easily create elements for your document

Suppose that we created a $document object

Create errors


// Create an error
$errorData = [
    'id' => 123,
    'status' => 500,
    'code' => 456,
    'title' => 'Test error'

// Return an error
$error = $document->makeError($errorData);

// Return multiple errors
$errors = [$document->makeError($errorData), $document->makeError($errorData)];

// Attach error to document
// Or
// It'll even work if you just put in an array data

Create links


$linkData = [
        'self' => $document->getUrl('self-url'),
        'ralated' => $document->getUrl('related-url')

// Create links
$links = $document->makeLinks($linkData);

// Attach links to document
// this will also work

// Create pagination
$pagination = $document->makePagination([
        'first' => $document->getUrl('first-link'),
        'last' => $document->getUrl('last-link'),
        'prev' => $document->getUrl('prev-link'),
        'next' => $document->getUrl('last-link'),

// Attach pagination to document

Create other elements

It'll work the same way, available methods are:

You can see more examples in /examples/index.php

Flexible document and resources

  • Flexible document can be used exactly like normal document, but $config is optional, flexible resource allowed... You can consider it as a "free schema" version of document.
  • Flexible document can use $config as normal document, then you can use it to work with flexible resource and mapped resource in the same document.
  • Flexible document might be helpful for projects with no ORM, build JSON API data quickly without configuration, build JSON API data to POST to another JSON API endpoint...
  • Flexible document is not recommended anyway, as it allows to build a document in a free way and may cause unpredicted errors to your API like missing elements, invalid format...etc... So use it carefully and wisely

Example of flexible document use


$flexibleDocument = new HackerBoy\JsonApi\Flexible\Document; // $config is the same format with normal document but it is optional

// Create a flexible resource
$flexibleResource = $flexibleDocument->makeFlexibleResource();
                        'attribute_name' => 'attribute value'
                        'meta-key' => 'meta value'
                        'self' => '/link'

// Attach flexible resource to document
$flexibleDocument->setData($flexibleResource); // You can put in a collection as well, all other methods are the same

echo $flexibleDocument->toJson();