# JSON:API Documents

# Introduction

Our default controller actions take care of returning JSON:API responses for you. However, there may be some scenarios where you want to customise the response.

Our Controller Hooks allow you to return a customised response for each of our action traits.

Alternatively, if you are implementing your own actions then you will also need to construct responses.

# Response Server

Laravel JSON:API supports applications having multiple JSON:API servers. To correctly encode a JSON:API compound document, the implementation needs to know which server to use.

Our JSON:API middleware takes care of setting the JSON:API server that is in use. This means if you are returning any response classes after this middleware has run, you do not need to tell the response which server must be used to encode the response.

If your application returns any of our JSON:API response classes in routes that either do not have the JSON:API middleware, or middleware that run before that middleware, you must explicitly set the server on the response. This can easily be done using the withServer() helper method. For example:

return DataResponse::make($model)->withServer('v1');

# Response Classes

We provide the following JSON:API response classes for returning responses that contain a JSON:API document in their body:

We also provide the Error Response class, which is covered in the errors chapter.

All these response classes have static make methods, so that you can fluently construct them. They also all implement our response helper methods, as described later in this chapter.

# Data Response

Our LaravelJsonApi\Core\Responses\DataResponse class is used when you need to return a resource, resources or null as the data member of a JSON:API document.

This response takes care of converting values to the correct JsonApiResource class. For example, if you provide an App\Models\Post model, it will convert this to a App\JsonApi\V1\Posts\PostResource to serialize it to the JSON:API format.

The same applies to any iterable value you provide. For example, if you provided a collection of Post models, it will take care of converting these models to the PostResource class when iterating over them.

To create a DataResponse, pass the value of the data member to the constructor, or the static make method if you need to chain any of our helper methods. For example:

use LaravelJsonApi\Core\Responses\DataResponse;

return new DataResponse($model);
// or
return DataResponse::make($model)
    ->withHeader('X-Foo', 'Bar')
    ->withMeta(['foo' => 'bar']);

# Create Resource Response

The JSON:API specification says that a response to a create resource request must have a Location header, and use the 201 Created HTTP response code.

For Eloquent models, we automatically detect this using the model's $wasRecentlyCreated property. When this is true, we add the Location header and set the status to 201.

If you need to manually force a DataResponse to be a create resource response, use the didCreate method:

return DataResponse::make($model)->didCreate();

Our LaravelJsonApi\Core\Responses\RelatedResponse class is used for the response to read the related resources in a relationship. E.g. GET /api/v1/posts/123/tags would read the related tags resources.

Like our other response classes, this class takes care of converting the value provided to the correct resource class, or converting values when iterating over them.

To create a related response, you need to provide three arguments:

  1. The model to which the relationship belongs;
  2. The JSON:API field name of the relationship; and
  3. The related value: either a model, models or null.

For example, given a post model, with a tags relationship:

use LaravelJsonApi\Core\Responses\RelatedResponse;

return new RelatedResponse($post, 'tags', $post->tags);
// or
return RelatedResponse::make($post, 'tags', $post->tags)
    ->withHeader('X-Foo', 'Bar')
    ->withMeta(['foo' => 'bar']);

By default this class will merge the relationship's meta into the top-level meta member of the JSON:API document. If you do not want this merging to occur, use the withoutRelationshipMeta() method, for example:

return RelatedResponse::make($post, 'tags', $post->tags)
  ->withoutRelationshipMeta();

# Relationship Response

Our LaravelJsonApi\Core\Responses\RelationshipResponse class is used for the response to a relationship endpoint, e.g. GET /api/v1/posts/123/relationships/tags. These endpoints return resource identifiers instead of resources.

Like other response classes, this class takes care of converting the value provided to the correct resource class, or converting values when iterating over them. It also adds the top-level relationship links to the JSON:API document in the response.

To create a relationship response, you need to provide three arguments:

  1. The model to which the relationship belongs;
  2. The JSON:API field name of the relationship; and
  3. The related value: either a model, models or null.

For example, given a post model, with a tags relationship:

use LaravelJsonApi\Core\Responses\RelationshipResponse;

return new RelationshipResponse($post, 'tags', $post->tags);
// or
return RelationshipResponse::make($post, 'tags', $post->tags)
    ->withHeader('X-Foo', 'Bar')
    ->withMeta(['foo' => 'bar']);

By default this class will merge the relationship's meta into the top-level meta member of the JSON:API document. If you do not want this merging to occur, use the withoutRelationshipMeta() method, for example:

return RelationshipResponse::make($post, 'tags', $post->tags)
  ->withoutRelationshipMeta();

# Meta Response

Our LaravelJsonApi\Core\Responses\MetaResponse class allows you to return a a JSON:API response that has a top-level meta member, but no data member. This is allowed by the specification.

To use this class, you just need to provide the meta value to either the constructor or the static make method. The meta value can be an array or a Laravel collection.

For example:

use LaravelJsonApi\Core\Responses\MetaResponse;

return new MetaResponse(['foo' => 'bar']);
// or
return MetaResponse::make(['foo' => 'bar'])
    ->withHeader('X-Foo', 'Bar');

# JSON:API Object

The JSON:API specification defines a jsonapi top-level member of a document. This can contain the JSON:API version the server is using, and may also include meta.

The content of this member is defined on your Server class. By default, it will generate the following jsonapi member:

{
  "jsonapi": {
    "version": "1.0"
  }
}

To customise this value, override the jsonApi method on your Server class:

namespace App\JsonApi\V1\Server;

use LaravelJsonApi\Core\Server\Server as BaseServer;

class Server extends BaseServer
{

    // ...

    public function jsonApi(): JsonApi
    {
      return JsonApi::make('1.0')->setMeta([
        'foo' => 'bar',
      ]);
    }
}

This would result in the following jsonapi member in your response documents:

{
  "jsonapi": {
    "version": "1.0",
    "meta": {
      "foo": "bar"
    }
  }
}

TIP

If you need to customise the jsonapi member for a specific response, use the withJsonApi helper method.

# Helper Methods

Our response classes have a number of helper methods, to enable you to customise the response. The available methods are:

# withServer

This method sets the JSON:API server that must be used when encoding the response to a JSON:API compound document. You do not need to use this method if the response is being returned after the JSON:API middleware has run. This is because the JSON:API middleware sets the server to use for all responses. Instead, use the withServer() method if you are returning a JSON:API response from a route that does not have the JSON:API middleware applied.

For example:

return DataResponse::make($model)->withServer('v1');

The string provided to the withServer() method is the server name used when registering servers in your JSON:API config file - as described in the Servers chapter.

# withJsonApi

The withJsonApi method allows you to override the default jsonapi object provided by your Server class.

For example:

use LaravelJsonApi\Core\Document\JsonApi;

return DataResponse::make($model)->withJsonApi(
  JsonApi::make('1.0')->withMeta(['foo' => 'bar'])
);

# withMeta

The withMeta method allows you to attach top-level meta to the JSON:API document. For example:

return DataResponse::make($model)->withMeta(['foo' => 'bar']);

The withLinks method allows you to attach top-level links objects to the JSON:API document. For example:

use LaravelJsonApi\Core\Document\Link;

return DataResponse::make($model)->withLinks(
    new Link('docs', 'https://www.example.com/api/docs')
);

As you can see from this example, the withLinks method will take a single Link object. If you want to set multiple links, use our Links object:

use LaravelJsonApi\Core\Document\Link;
use LaravelJsonApi\Core\Document\Links;

return DataResponse::make($model)->withLinks(new Links(
    new Link('docs', 'https://www.example.com/api/docs'),
    new Link('misc', 'https://www.example.com/api/misc')
));

WARNING

The JSON:API specification is not entirely clear as to what links are actually allowed at the top-level, beyond a self link and pagination links (first, last, prev, next). More links might be added to the specification in the future, so it is potentially risky adding your own links at the current time.

# withEncodeOptions

The withEncodeOptions sets the JSON encoding option flags. These are the flags used by PHP's json_encode function. (opens new window).

For example:

return DataResponse::make($model)
    ->withEncodeOptions(JSON_UNESCAPED_UNICODE);

# withHeader

The withHeader method allows you to set a single header on the response:

return DataResponse::make($model)->withHeader('X-Foo', 'Bar');

# withHeaders

The withHeaders method allows you to set multiple headers on the response:

return DataResponse::make($model)->withHeaders([
  'X-Foo' => 'Bar',
  'X-Baz' => 'Bat',
]);
Last Updated: 5/17/2023, 7:50:00 PM