Tim MacDonald's JSON API
timacdonald/json-api
is a great package that allows you to implement a JSON:API-compliant API with Laravel.
Scramble has timacdonald/json-api
support as part of the Scramble PRO package. You can get Scramble PRO here: https://scramble.dedoc.co/pro. After purchasing, you will receive the license key in your email.
The best demo of Scramble PRO’s timacdonald/json-api
support is Cachet, an open-source status page system:
Note that Cachet uses a bit of custom setup for rendering the API reference: after the OpenAPI document is generated, it is committed to another repo where Mintlify takes care of rendering it.
Installation
Before installing Scramble PRO, make sure to update dedoc/scramble
to at least 0.12.23
.
Add the private repository to the list of your repositories in composer.json
"repositories": [ { "type": "composer", "url": "https://satis.dedoc.co" }],
Now, add the package to the list of your dependencies:
"require": { "dedoc/scramble-pro": "^0.7.9", "dedoc/scramble": "^0.12.23",}
And run composer update
.
When running composer update, you will be prompted to provide your credentials for the repository website. These credentials will authenticate your Composer session as having permission to download the Scramble PRO source code. To avoid manually typing these credentials, you may create a Composer auth.json file and use your license key in place of the password:
{ "http-basic": { "satis.dedoc.co": { "username": "youremail@company.com", "password": "YOUR-KEY-000000" } }}
You may quickly create an auth.json file via your terminal using the following command.
composer config http-basic.satis.dedoc.co \ youremail@company.com \ YOUR-KEY-000000
You should not commit your application’s auth.json
file into source control!
Using JSON API resources
Whenever you return a JSON API resource from a controller method, Scramble will infer the returned type and document the response of the corresponding API endpoint.
This covers both singular JSON API resources and resource collections.
use App\Http\Resources\UserResource;use App\Models\User;
class UserController{ public function index() { $users = User::with([/* ... */])->paginate();
return UserResource::collection($users); }
public function show(User $user) { $user->load([/* ... */]);
return UserResource::make($user); }}
Resource’s model
When using JSON API resources, Scramble can infer the types of attributes or relationships by guessing the associated resource’s model using Laravel’s conventions. For example, when analyzing App\Http\Resources\UserResource
, Scramble will assume that the corresponding model is App\Models\User
(or App\User
). If such a model class exists, it will be used to document the types of attributes and relationships.
You can provide a model associated with a resource class manually by annotating the resource class with the model class using @mixin
, @property
, or @property-read
PHPDoc annotations:
use TiMacDonald\JsonApi\JsonApiResource;use App\Domains\Admin\Models\User;
/** @mixin User */class UserResource extends JsonApiResource{ // ...}
Or using @property
:
use TiMacDonald\JsonApi\JsonApiResource;use App\Domains\Admin\Models\User;
/** @property User $resource */class UserResource extends JsonApiResource{ // ...}
Or using @property-read
:
use TiMacDonald\JsonApi\JsonApiResource;use App\Domains\Admin\Models\User;
/** @property-read User $resource */class UserResource extends JsonApiResource{ // ...}
When inferring attribute and relationship types, Scramble analyzes the model’s table in the database using your default database connection (just like Laravel’s model:show
command does). So, to get correct results, make sure you have all your migrations applied to the database.
Attributes
Scramble supports documenting attributes defined both via the $attributes
property and via the toAttributes
method.
use TiMacDonald\JsonApi\JsonApiResource;
class UserResource extends JsonApiResource{ public $attributes = [ 'name', 'email', ];}
You can add documentation to each attribute by adding a comment above the corresponding attribute. This can include a description, an example, a default value (just in case you need it!), a format, and even a type.
use TiMacDonald\JsonApi\JsonApiResource;
class UserResource extends JsonApiResource{ public $attributes = [ // The name of a user 'name', /** * The email of a user * @format email * @var string|null * @example test@example.com * @default probablynotagoodexample@example.com */ 'email', ];}
The toAttributes
method is also supported:
use TiMacDonald\JsonApi\JsonApiResource;
class UserResource extends JsonApiResource{ public function toAttributes() { return [ 'name' => $this->name, 'email' => $this->email, ]; }}
Adding manual documentation to attributes defined in the toAttributes
method works the same way as for the $attributes
property: you just add a comment above the attribute:
use TiMacDonald\JsonApi\JsonApiResource;
class UserResource extends JsonApiResource{ public function toAttributes() { return [ // The name of a user 'name' => $this->name, /** * The email of a user * @format email * @var string|null * @example test@example.com * @default probablynotagoodexample@example.com */ 'email' => $this->email, ]; }}
Relationships
Scramble supports documenting relationships defined both via the $relationships
property and via the toRelationships
method.
use TiMacDonald\JsonApi\JsonApiResource;
class UserResource extends JsonApiResource{ public $relationships = [ 'posts' => PostResource::class, 'profile' => ProfileResource::class, ];}
By default, timacdonald/json-api
supports a relationships convention: if your resource’s class follows the '{myKey}' => {MyKey}Resource::class
naming, you can omit the full resource class name. Scramble supports this too:
use TiMacDonald\JsonApi\JsonApiResource;
class UserResource extends JsonApiResource{ public $relationships = [ 'posts', 'profile', ];}
The toRelationships
method is also supported:
<?php
namespace App\Http\Resources;
use TiMacDonald\JsonApi\JsonApiResource;
class UserResource extends JsonApiResource{ public function toRelationships($request) { return [ 'posts' => fn () => $request->user()->is($this->resource) ? PostResource::collection($this->posts) : PostResource::collection($this->posts->where('published', true)), 'profile' => fn () => ProfileResource::make($this->profile), ]; }}
Links
Note: The
toLinks
resource method is documented under the//----- Everything that follows is WIP and should be ignored ------- //
section in thetimacdonald/json-api
documentation, so its behavior can be changed.
Scramble supports documenting resource links defined in the toLinks
resource method.
For every link, you can add a description and an example using a comment (both simple comments and PHPDoc comments).
use TiMacDonald\JsonApi\JsonApiResource;use TiMacDonald\JsonApi\Link;
class UserResource extends JsonApiResource{ public function toLinks($request): array { return [ Link::self(route('api.users.show', $this->resource)), // Related user Link::related(route('api.users.show', $this->resource->parent), ['foo' => 'bar']), /** * @example {"href":"https://api.example.com/user/1","meta":{"foo":42}} */ new Link('user', 'https://example.com/user/1', ['foo' => 'bar']), ]; }}
When documenting links, Scramble will follow the JSON:API specification and document them as link objects: https://jsonapi.org/format/#document-links-link-object
While resource links in the JSON:API specification can also be a string
or null
, currently you can only use a link object (toArray
method MUST return array<int, Link>
) when using timacdonald/json-api
, hence Scramble documents it as a link object.
Not implemented features (yet)
When consuming API endpoints with timacdonald/json-api
resources, sometimes you can provide query parameters (includes, sparse fieldsets). Scramble PRO currently does not document these query parameters.
Also, the toMeta
resource method is not yet supported.
Let me know if you need support for these features: roman@dedoc.co.