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

Eloquent Laravel Package

laravel-json-api/eloquent

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require laravel-json-api/eloquent
    

    Publish the config (optional but recommended for customization):

    php artisan vendor:publish --provider="JsonApi\Laravel\JsonApiServiceProvider" --tag=config
    
  2. Basic Usage Define a resource class (e.g., app/Http/Resources/UserResource.php):

    namespace App\Http\Resources;
    
    use JsonApi\Laravel\ResourceObject;
    use App\Models\User;
    
    class UserResource extends ResourceObject
    {
        public static $resourceKey = 'users';
        public static $shortName = 'user';
    
        public function getAttributes(User $user)
        {
            return [
                'name' => $user->name,
                'email' => $user->email,
            ];
        }
    }
    
  3. First API Response In a controller:

    use App\Http\Resources\UserResource;
    use App\Models\User;
    
    public function index()
    {
        return UserResource::collection(User::all());
    }
    

    This returns a standardized JSON:API response:

    {
        "data": [
            {
                "type": "users",
                "id": "1",
                "attributes": {
                    "name": "John Doe",
                    "email": "[email protected]"
                }
            }
        ]
    }
    
  4. Key Files to Review

    • config/json-api.php: Global configuration (e.g., default meta fields, pagination).
    • app/Http/Resources/: Your resource classes.
    • JsonApi\Laravel\ResourceObject: Base class for customization.

Implementation Patterns

1. Resource Organization

  • Group by Model: Create a Resources directory with subdirectories (e.g., Users, Posts) for scalability.
  • Shared Attributes: Extend base resources for DRY logic:
    abstract class BaseResource extends ResourceObject
    {
        public function getMeta()
        {
            return ['created_at' => $this->resource->created_at];
        }
    }
    

2. Relationships

  • To-One: Define in getRelationshipData():
    public function getRelationshipData($key)
    {
        return $this->whenLoaded($key, function () use ($key) {
            return $this->{$key} ? new PostResource($this->{$key}) : null;
        });
    }
    
  • To-Many: Use ResourceObject::collection():
    public function getRelationshipData($key)
    {
        return $this->whenLoaded($key, function () use ($key) {
            return PostResource::collection($this->{$key});
        });
    }
    

3. Filtering, Sorting, and Pagination

  • Query Scoping: Use JsonApi\Laravel\Query\QueryBuilder in controllers:
    use JsonApi\Laravel\Query\QueryBuilder;
    
    public function index(Request $request)
    {
        $query = QueryBuilder::for(User::class)
            ->allowedFilters(['name', 'email'])
            ->allowedSorts(['name', 'created_at'])
            ->paginate();
    
        return UserResource::collection($query->get());
    }
    
  • Custom Filters: Override JsonApi\Laravel\Query\Filter:
    public function apply($query, $value)
    {
        return $query->where('name', 'like', "%{$value}%");
    }
    

4. Meta and Links

  • Add Meta: Override getMeta() in resources:
    public function getMeta()
    {
        return [
            'custom_field' => $this->resource->custom_field,
            'links' => [
                'self' => route('users.show', $this->resource),
            ],
        ];
    }
    
  • Global Meta: Configure in config/json-api.php:
    'meta' => [
        'version' => '1.0',
    ],
    

5. Testing

  • Unit Tests: Mock resources:
    $user = new User();
    $resource = new UserResource($user);
    $this->assertEquals('John Doe', $resource->name);
    
  • API Tests: Use JsonApiTestCase (if provided) or Http::fake():
    $response = $this->getJson('/api/users');
    $response->assertJsonStructure([
        'data' => [
            '*' => ['type', 'id', 'attributes']
        ]
    ]);
    

Gotchas and Tips

Common Pitfalls

  1. N+1 Queries

    • Problem: Eager-loading relationships isn’t automatic.
    • Fix: Use with() in queries or whenLoaded() in resources:
      $users = User::with('posts')->get();
      // OR
      $resource->whenLoaded('posts', fn() => PostResource::collection($this->posts));
      
  2. Circular References

    • Problem: Bidirectional relationships (e.g., User->posts and Post->user) cause infinite loops.
    • Fix: Use shouldSerialize() or exclude in getRelationshipData():
      public function getRelationshipData($key)
      {
          return $this->whenLoaded($key, function () use ($key) {
              return $key === 'user' ? null : PostResource::collection($this->posts);
          });
      }
      
  3. ID Type Mismatch

    • Problem: JSON:API expects IDs as strings, but Eloquent may use integers.
    • Fix: Cast in getId():
      public function getId($model)
      {
          return (string) $model->id;
      }
      
  4. Pagination Conflicts

    • Problem: Default pagination (e.g., Laravel’s paginate()) may not align with JSON:API.
    • Fix: Use JsonApi\Laravel\Query\QueryBuilder for consistent pagination:
      $query->paginate(10); // Returns JSON:API-compliant pagination headers.
      

Debugging Tips

  • Enable Debugging: Set 'debug' => true in config/json-api.php to log resource serialization.
  • Inspect Serialized Data: Use dd($resource->resolve()) to see raw output before JSON encoding.
  • Check Headers: Verify Content-Type: application/vnd.api+json is set in responses.

Extension Points

  1. Custom Serializers Override JsonApi\Laravel\Serializers\ResourceSerializer for global changes (e.g., date formatting):

    public function serialize($resource)
    {
        $data = parent::serialize($resource);
        $data['attributes']['created_at'] = $resource->created_at->toIso8601String();
        return $data;
    }
    
  2. Middleware for Auth Use middleware to attach auth data to meta:

    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $response->getData()->setMeta('auth', ['user_id' => auth()->id()]);
        return $response;
    }
    
  3. Dynamic Resource Keys Use closures in getResourceKey() for dynamic keys:

    public function getResourceKey($model)
    {
        return $model->is_admin ? 'admins' : 'users';
    }
    

Performance Optimizations

  • Caching: Cache resource collections:
    return Cache::remember("users.{$request->query()}", now()->addHours(1), function () {
        return UserResource::collection(User::all());
    });
    
  • Lazy Loading: Use JsonApi\Laravel\LazyLoad for large datasets:
    $resource = new UserResource(User::find(1));
    $resource->lazyLoad('posts');
    
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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle