Laravel JSON:API Documentation

repository·develop·Indexed 20 days ago

https://github.com/laravel-json-api/laravel

A tool for implementing standards-compliant JSON:API endpoints within Laravel applications. It provides expressive schemas to define fields, relationships, filters, and pagination, along with Artisan commands like jsonapi:query and jsonapi:server for scaffolding. The library includes specialized FormRequest and ResourceRequest classes for media type detection, action identification, and resource-specific authorization and validation.

Tokens
7.8K
Snippets
28
Records
33
Agent score
67%

What's inside Laravel JSON:API

  1. Define a resource schema

    develop

    Schemas are the core of Laravel JSON:API. They define how your Eloquent models are exposed via the API. You define fields (including relationships), filters, and pagination within a class extending Schema.

    Key components of a schema include:

    • $model: The Eloquent model class this schema represents.
    • fields(): An array of field definitions using types like ID, Str, DateTime, BelongsTo, HasMany, and BelongsToMany.
    • filters(): An array of available filters (e.g., WhereIdIn, WhereIn).
    • pagination(): Defines the pagination strategy (e.g., PagePagination).
    class PostSchema extends Schema
    {
        /**
         * The model the schema corresponds to.
         *
         * @var string
         */
        public static string $model = Post::class;
    
        /**
         * The maximum include path depth.
         *
         * @var int
         */
        protected int $maxDepth = 3;
    
        /**
         * Get the resource fields.
         *
         * @return array
         */
        public function fields(): array
        {
            return [
                ID::make(),
                BelongsTo::make('author')->type('users')->readOnly(),
                HasMany::make('comments')->readOnly(),
                Str::make('content'),
                DateTime::make('createdAt')->sortable()->readOnly(),
                DateTime::make('publishedAt')->sortable(),
                Str::make('slug'),
                BelongsToMany::make('tags'),
                Str::make('title')->sortable(),
                DateTime::make('updatedAt')->sortable()->readOnly(),
            ];
        }
    
        /**
         * Get the resource filters.
         *
         * @return array
         */
        public function filters(): array
        {
            return [
                WhereIdIn::make($this),
                WhereIn::make('author', 'author_id'),
            ];
        }
    
        /**
         * Get the resource paginator.
         *
         * @return Paginator|null
         */
        public function pagination(): ?Paginator
        {
            return PagePagination::make();
        }
    }
  2. Upgrade Laravel JSON:API and related packages

    develop

    When upgrading, it is recommended to upgrade the core package and all related packages (such as testing utilities) simultaneously to ensure compatibility. Use the --no-update flag to stage the requirements before running the update.

    composer require laravel-json-api/laravel --no-update
    composer require laravel-json-api/testing --dev --no-update
    composer up "laravel-json-api/*" cloudcreativity/json-api-testing
  3. Authorize JSON:API requests

    develop

    The FormRequest class handles authorization by checking for specific methods. You can implement authorization in two ways:

    1. Custom Authorization: Implement the authorize() method. If it returns a boolean, that result is used. If it returns a Laravel Response object, the response's authorization status is used.
    2. Resource Authorization: Implement the authorizeResource() method to handle authorization specifically for the resource context.

    If no authorization methods are implemented, the class will attempt to run default authorization if enabled for the server and the schema.

    If authorization fails and the user is not authenticated, the request will throw an AuthenticationException.

  4. Extend FormRequest for JSON:API

    develop

    When building custom validation or authorization logic for JSON:API endpoints, extend LaravelJsonApi\Laravel\Http\Requests\FormRequest instead of the standard Laravel BaseFormRequest. This specialized class provides helper methods to detect JSON:API media types and determine the specific JSON:API action being performed (e.g., viewing a relationship, updating a resource, or attaching to a relationship).

    Key capabilities include:

    • Media Type Detection: Methods like isJsonApi(), wantsJsonApi(), and acceptsJsonApi() check for the application/vnd.api+json content type.
    • Action Detection: Methods like isCreating(), isUpdating(), isViewingRelated(), and isAttachingRelationship() allow you to branch logic based on the JSON:API request intent.
    • Schema Access: The schema() method provides direct access to the Schema instance associated with the current route.
    • Relationship Context: getFieldName() returns the name of the relationship if the request is targeting a relationship endpoint.
    <?php
    
    namespace App\Http\Requests;
    
    use LaravelJsonApi\Laravel\Http\Requests\FormRequest;
    
    class CreatePostRequest extends FormRequest
    {
        public function rules(): array
        {
            return [
                'title' => 'required|string',
            ];
        }
    }
  5. Define custom controller actions for relationships

    develop

    By default, relationship routes point to standard methods. If you want specific relationship actions to trigger unique, named methods on your controller, use ownAction() or ownActions().

    • ownAction(...$actions): Specifies a list of actions that should have their own named controller methods.
    • ownActions(): A helper that specifies related, show, update, attach, and detach as having their own named actions.
    $registrar->relationship('followers')
        ->ownAction('attach', 'detach')
        ->register();
  6. Resolve query parameters for many or one resources

    develop

    You can programmatically resolve the ResourceQuery instance (which implements QueryParameters) for a specific resource type. This is useful when you need to access query parameters like filter, sort, or include outside of a standard controller method.

    Use ResourceQuery::queryMany($resourceType) when querying a collection of resources, and ResourceQuery::queryOne($resourceType) when querying a single resource.

    use LaravelJsonApi//Laravel//Http/Requests/ResourceQuery;
    
    // For a collection request
    $queryMany = ResourceQuery::queryMany('articles');
    
    // For a single resource request
    $queryOne = ResourceQuery::queryOne('articles');
  7. Retrieve the model for a resource request

    develop

    Within a ResourceRequest, you can access the underlying Eloquent model associated with the current route.

    • Use model() to get the model if the URL contains a resource ID, or null otherwise.
    • Use modelOrFail() to get the model or throw a LogicException if no model is present (e.g., on a POST request to a collection).

    These methods are essential for performing logic that depends on the specific record being targeted.

    // Inside a ResourceRequest class
    public function someMethod()
    {
        $model = $this->modelOrFail();
        // ...
    }
  8. Configure middleware for resource routes

    develop

    The middleware() method allows you to apply middleware to your resource routes. It supports two modes:

    1. Global Middleware: Pass a simple array or list of strings to apply middleware to all routes generated for the resource.
    2. Action-Specific Middleware: Pass an associative array where the key * represents middleware applied to all actions, and other keys represent middleware applied to specific actions.

    You can also use withoutMiddleware(...$middleware) to explicitly remove specific middleware from the resource routes.

    // Apply middleware to all resource routes
    $router->resource('articles')->middleware('auth:api');
    
    // Apply specific middleware to all actions and others to specific ones
    $router->resource('articles')->middleware([
        '*' => ['web'],
        'store' => ['throttle:60,1'],
    ]);
    
    // Remove middleware
    $router->resource('articles')->withoutMiddleware('guest');
  9. Configure resource routes using PendingResourceRegistration

    develop

    When registering a resource in Laravel JSON:API, you can use the fluent API provided by PendingResourceRegistration to customize the generated routes. This allows you to filter which controller methods are exposed, set custom route names, override parameters, and manage middleware.

    Common customization tasks include:

    • Filtering actions: Use only() to specify which methods to include or except() to exclude specific ones. Use readOnly() as a shortcut for only('index', 'show').
    • Naming routes: Use name() to set a specific name for a method, or names() to set multiple names at once. Note that certain aliases are mapped: create maps to store, read maps to show, and delete maps to destroy.
    • Parameter customization: Use parameter() to change the route parameter name.
    • Middleware management: Use middleware() to add middleware (either globally for all resource routes or specifically for actions using the * key) and withoutMiddleware() to exclude specific middleware.
    • Relationships and Actions: Use relationships() to define relationship-specific routes via a callback, and actions() to define custom resource actions.
    $router->resource('articles')
        ->only(['index', 'show'])
        ->middleware('auth:api')
        ->parameter('article')
        ->register();
  10. Register custom resource actions with ActionRegistrar

    develop

    The ActionRegistrar provides a fluent API for defining custom HTTP routes for a specific JSON:API resource. It handles URI normalization, controller action guessing, and automatic parameter injection (like resource IDs).

    Key Features

    • HTTP Method Helpers: Use get(), post(), patch(), put(), delete(), and options() to register routes.
    • ID-based Routes: By default, routes are registered relative to the resource collection. Calling withId() tells the registrar to include the resource's ID parameter in the URI (e.g., /{id}/your-action).
    • Automatic Action Guessing: If no specific controller action is provided, the registrar converts the URI segment into a camelCase string to use as the method name on your controller.
    • Parameter Management: When withId() is used, the registrar automatically resolves the correct resource parameter name based on your resource configuration.
    // Example of registering a custom action on a resource
    $resource->get('publish', 'publishAction') // GET /articles/publish
        ->withId()                             // GET /articles/{id}/publish
        ->post('archive');                    // POST /articles/{id}/archive
  11. Use withId() to include resource identifiers in routes

    develop

    When registering an action, calling withId() modifies the route URI to include the resource's unique identifier parameter. This is necessary for actions that must be performed on a specific resource instance rather than the collection.

    Without withId(): The URI is relative to the resource collection (e.g., /articles/my-action). With withId(): The URI includes the resource parameter (e.g., /articles/{article}/my-action).

    // Registering an action that requires a specific resource ID
    $registrar->post('reset-password')->withId();