Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Json Api Laravel Package

api-platform/json-api

JSON:API component for the API Platform framework. Adds JSON:API-compliant request/response handling and content negotiation for building standardized JSON APIs. Read-only split of api-platform/core; issues and PRs belong in the core repository.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install API Platform Core (this package is a subcomponent):

    composer require api-platform/core
    

    (Note: This is a read-only split; use the core package directly.)

  2. Configure Laravel Integration Install the Laravel adapter and enable the JSON:API extension:

    composer require api-platform/laravel
    

    Update config/app.php to include:

    ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
    
  3. Annotate a Resource Create a simple entity with #[ApiResource]:

    // src/Entity/Post.php
    use ApiPlatform\Core\Annotation\ApiResource;
    
    #[ApiResource]
    class Post {
        public string $title;
        public string $content;
    }
    
  4. Test the Endpoint Visit /api/posts to see JSON:API formatted output:

    {
      "data": [
        {
          "type": "posts",
          "id": "1",
          "attributes": {
            "title": "Hello World",
            "content": "..."
          }
        }
      ]
    }
    
  5. Enable JSON:API Content Negotiation Add this to config/packages/api_platform.yaml:

    api_platform:
        formats:
            jsonapi: ['application/vnd.api+json']
        patch_formats:
            jsonapi: ['application/vnd.api+json']
    

First Use Case: Sparse Fieldsets

Request only specific fields via query parameters:

GET /api/posts?fields[posts]=title

Response:

{
  "data": [
    {
      "type": "posts",
      "id": "1",
      "attributes": {
        "title": "Hello World"
      }
    }
  ]
}

Implementation Patterns

1. Resource Configuration

Define operations and serialization groups in #[ApiResource]:

#[ApiResource(
    collectionOperations: ['get' => ['method' => 'GET', 'path' => '/posts']],
    itemOperations: ['get', 'put' => ['method' => 'PATCH']],
    normalizationContext: ['groups' => ['post:read']],
    denormalizationContext: ['groups' => ['post:write']]
)]
class Post { ... }

2. Relationship Handling

Use #[ApiProperty] and #[ApiRelation] for nested resources:

use ApiPlatform\Core\Annotation\ApiRelation;

#[ApiResource]
class Post {
    #[ApiRelation(
        attribute: 'author',
        collection: false,
        embedded: true,
        normalizationContext: ['groups' => ['author:read']]
    )]
    public ?User $author;
}

3. Custom Serialization Context

Override default serialization via middleware or event listeners:

// src/EventListener/AddCustomContext.php
use ApiPlatform\Core\EventListener\JsonLdContextBuilder;

class AddCustomContext implements JsonLdContextBuilder {
    public function __invoke($context, UrlGeneratorInterface $urlGenerator) {
        $context['@context'] = '/api/contexts/Post';
        return $context;
    }
}

4. Pagination

Leverage built-in pagination (default: 30 items):

# config/packages/api_platform.yaml
api_platform:
    pagination_enabled: true
    pagination_client_items_per_page: true

Request with custom page size:

GET /api/posts?page[size]=10

5. Filtering and Sorting

Use query parameters for dynamic filtering:

GET /api/posts?filter[title][contains]=Hello&order[title]=ASC

6. Error Handling

JSON:API errors are automatically formatted per RFC 7807:

{
  "errors": [
    {
      "title": "Validation Failed",
      "detail": "The title field is required.",
      "source": { "pointer": "/data/attributes/title" },
      "code": "422"
    }
  ]
}

7. Integration with Laravel Services

Use dependency injection to access the JSON:API serializer:

use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
use Symfony\Component\Serializer\SerializerInterface;

class PostController {
    public function __construct(
        private SerializerInterface $serializer,
        private SerializerContextBuilderInterface $contextBuilder
    ) {}

    public function show(Post $post) {
        $context = $this->contextBuilder->createFromRequest(null, false);
        return $this->serializer->serialize($post, 'jsonapi', $context);
    }
}

8. Testing JSON:API Responses

Use Laravel’s HTTP tests with JSON:API assertions:

public function testJsonApiResponse() {
    $response = $this->getJson('/api/posts');

    $response->assertStatus(200)
             ->assertJsonStructure([
                 'data' => [
                     ['type', 'id', 'attributes' => ['title', 'content']]
                 ]
             ]);
}

Gotchas and Tips

Pitfalls

  1. Symfony Dependency Conflicts

    • Issue: Laravel’s DI container may clash with Symfony’s autowiring.
    • Fix: Explicitly bind services in config/services.php:
      ApiPlatform\Core\Serializer\SerializerContextBuilderInterface::class => \App\CustomContextBuilder::class,
      
  2. Missing JSON:API Headers

    • Issue: Responses lack Content-Type: application/vnd.api+json.
    • Fix: Ensure Accept header is set or configure default format:
      # config/packages/api_platform.yaml
      api_platform:
          formats:
              jsonapi: ['application/vnd.api+json']
          default_formats: ['jsonapi']
      
  3. Relationship Serialization Issues

    • Issue: Nested resources fail to serialize.
    • Fix: Use embedded: true and ensure proper #[Groups]:
      #[ApiRelation(embedded: true, normalizationContext: ['groups' => ['author:read']])]
      
  4. Pagination Quirks

    • Issue: page[size] is ignored.
    • Fix: Enable client-controlled pagination:
      api_platform:
          pagination_client_items_per_page: true
      
  5. Circular References

    • Issue: Infinite loops in recursive relationships.
    • Fix: Use #[MaxDepth] or customize the serializer:
      $context = $this->contextBuilder->createFromRequest(null, false, ['max_depth' => 2]);
      

Debugging Tips

  1. Inspect Serialization Context Dump the context to debug field inclusion:

    $context = $this->contextBuilder->createFromRequest($request, false);
    dd($context);
    
  2. Enable API Platform Debug Toolbar Install the Symfony Profiler bundle for serialization insights:

    composer require symfony/profiler-pack
    
  3. Validate JSON:API Output Use jsonapi.tools to validate responses.

  4. Check for Deprecated Attributes Replace #[ApiProperty] with #[ApiResource] operations where applicable.


Configuration Quirks

  1. Default Pagination Override in config/packages/api_platform.yaml:

    api_platform:
        pagination_items_per_page: 20
    
  2. Custom Context Paths Define global context files:

    api_platform:
        jsonld_context:
            paths:
                - '%kernel.project_dir%/config/api_context.jsonld'
    
  3. Disable JSON:API for Specific Resources Use denormalizationContext to exclude:

    #[ApiResource(
        normalizationContext: ['enable_max_depth' => false]
    )]
    

Extension Points

  1. Custom Serializer Extend JsonApiSerializer for domain-specific logic:

    use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
    
    class CustomJsonApiSerializer extends JsonApiSerializer {
        public function serialize($data, string $format, array $context = []) {
            // Custom logic here
            return parent::serialize($data, $format, $context);
        }
    }
    
  2. Event Listeners Modify responses via events (e.g., ApiPlatform\EventListener\JsonLdResponseContextListener):

    use ApiPlatform\Core\EventListener\JsonLdResponseContextListener;
    
    class CustomContextListener extends JsonLdResponseContextListener {
        public function __invoke($event, $format, array $context = []) {
            $context['custom_key'] = 'value';
            return $context;
        }
    }
    
  3. Dynamic Metadata Add runtime metadata to responses:

    use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
    
    class DynamicMetadataFactory implements
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor