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.13.10.
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.8.5", "dedoc/scramble": "^0.13.10",}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-000000You 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.
1use App\Http\Resources\UserResource;2use App\Models\User;3
4class UserController5{6 public function index()7 {8 $users = User::with([/* ... */])->paginate();9
10 return UserResource::collection($users);11 }12
13 public function show(User $user)14 {15 $user->load([/* ... */]);16
17 return UserResource::make($user);18 }19}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:
1use TiMacDonald\JsonApi\JsonApiResource;2use App\Domains\Admin\Models\User;3
4/** @mixin User */5class UserResource extends JsonApiResource6{7 // ...8}Or using @property:
1use TiMacDonald\JsonApi\JsonApiResource;2use App\Domains\Admin\Models\User;3
4/** @property User $resource */5class UserResource extends JsonApiResource6{7 // ...8}Or using @property-read:
1use TiMacDonald\JsonApi\JsonApiResource;2use App\Domains\Admin\Models\User;3
4/** @property-read User $resource */5class UserResource extends JsonApiResource6{7 // ...8}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.
1use TiMacDonald\JsonApi\JsonApiResource;2
3class UserResource extends JsonApiResource4{5 public $attributes = [6 'name',7 'email',8 ];9}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.
1use TiMacDonald\JsonApi\JsonApiResource;2
3class UserResource extends JsonApiResource4{5 public $attributes = [6 // The name of a user7 'name',8 /**9 * The email of a user10 * @format email11 * @var string|null12 * @example test@example.com13 * @default probablynotagoodexample@example.com14 */15 'email',16 ];17}The toAttributes method is also supported:
1use TiMacDonald\JsonApi\JsonApiResource;2
3class UserResource extends JsonApiResource4{5 public function toAttributes()6 {7 return [8 'name' => $this->name,9 'email' => $this->email,10 ];11 }12}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:
1use TiMacDonald\JsonApi\JsonApiResource;2
3class UserResource extends JsonApiResource4{5 public function toAttributes()6 {7 return [8 // The name of a user9 'name' => $this->name,10 /**11 * The email of a user12 * @format email13 * @var string|null14 * @example test@example.com15 * @default probablynotagoodexample@example.com16 */17 'email' => $this->email,18 ];19 }20}Relationships
Scramble supports documenting relationships defined both via the $relationships property and via the toRelationships method.
1use TiMacDonald\JsonApi\JsonApiResource;2
3class UserResource extends JsonApiResource4{5 public $relationships = [6 'posts' => PostResource::class,7 'profile' => ProfileResource::class,8 ];9}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:
1use TiMacDonald\JsonApi\JsonApiResource;2
3class UserResource extends JsonApiResource4{5 public $relationships = [6 'posts',7 'profile',8 ];9}The toRelationships method is also supported:
1<?php2
3namespace App\Http\Resources;4
5use TiMacDonald\JsonApi\JsonApiResource;6
7class UserResource extends JsonApiResource8{9 public function toRelationships($request)10 {11 return [12 'posts' => fn () => $request->user()->is($this->resource)13 ? PostResource::collection($this->posts)14 : PostResource::collection($this->posts->where('published', true)),15 'profile' => fn () => ProfileResource::make($this->profile),16 ];17 }18}Links
Note: The
toLinksresource method is documented under the//----- Everything that follows is WIP and should be ignored ------- //section in thetimacdonald/json-apidocumentation, 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).
1use TiMacDonald\JsonApi\JsonApiResource;2use TiMacDonald\JsonApi\Link;3
4class UserResource extends JsonApiResource5{6 public function toLinks($request): array7 {8 return [9 Link::self(route('api.users.show', $this->resource)),10 // Related user11 Link::related(route('api.users.show', $this->resource->parent), ['foo' => 'bar']),12 /**13 * @example {"href":"https://api.example.com/user/1","meta":{"foo":42}}14 */15 new Link('user', 'https://example.com/user/1', ['foo' => 'bar']),16 ];17 }18}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.