othyn/filament-api-resources
Installation:
composer require othyn/filament-api-resources
(Note: Due to Filament V4's native API support, this package may not be actively maintained. Verify compatibility with your Filament version.)
Basic API Resource Definition:
Create a custom API resource class extending Filament\ApiResource:
use Othyn\FilamentApiResources\ApiResource;
class UserApiResource extends ApiResource
{
public static function getEndpoint(): string
{
return 'https://api.example.com/users';
}
public static function getModel(): string
{
return \stdClass::class; // Dummy model for type hints
}
}
Register in Filament Panel:
use Othyn\FilamentApiResources\Filament\Resources\ApiResourcePanel;
ApiResourcePanel::make()
->id('api-panel')
->resources([
UserApiResource::class,
]);
First Use Case: Use the resource in a Filament page:
use Filament\Tables\Table;
Table::make()
->query(UserApiResource::query())
->columns([
// Define columns as usual
]);
API Integration:
getEndpoint() and handle responses via transform().getHeaders() to inject auth tokens:
public static function getHeaders(): array
{
return ['Authorization' => 'Bearer ' . config('services.api.token')];
}
Data Transformation:
transform() to map API responses to Filament-compatible data:
public function transform($record): array
{
return [
'id' => $record->id,
'name' => $record->attributes->name,
];
}
Pagination:
getPagination():
public static function getPagination(): string
{
return 'custom'; // Use 'links' for API pagination links
}
CRUD Operations:
create(), update(), and delete() to handle API calls:
public static function create(array $data): array
{
return http_post(self::getEndpoint(), $data)->json();
}
Relationships: Use hasManyThrough() or belongsTo() with API endpoints:
public static function posts(): HasManyThrough
{
return self::hasManyThrough(
PostApiResource::class,
'relationship_endpoint',
'id',
'user_id'
);
}
Policy Integration: Bind API resources to gates/policies:
Gate::define('view-user', function ($user, $record) {
return http_get("{$record->endpoint}/{$record->id}/permissions")
->contains('view');
});
Real-Time Updates:
Poll API for changes using refresh():
public function refresh()
{
$this->setData(http_get(self::getEndpoint())->json());
}
Deprecation Risk:
Caching Quirks:
getCacheDuration() or use Laravel’s cache middleware:
public static function getCacheDuration(): int
{
return 300; // 5 minutes
}
Pagination Conflicts:
?page=1) may clash with Filament’s built-in pagination. Use getPagination() to enforce consistency:
public static function getPagination(): string
{
return 'cursor'; // For GraphQL-style pagination
}
Type Safety:
stdClass as a placeholder model. For stricter typing, define a DTO:
class UserDto { public int $id; public string $name; }
public static function getModel(): string { return UserDto::class; }
Http::withOptions(['debug' => true]);
transform():
dd($record); // Debug API response structure
try {
return http_get(self::getEndpoint())->json();
} catch (\Throwable $e) {
throw new \Exception("API Error: {$e->getMessage()}");
}
Custom HTTP Client:
Override getHttpClient() to use Guzzle with custom config:
public static function getHttpClient(): \Illuminate\Http\Client\PendingRequest
{
return Http::withOptions(['timeout' => 30]);
}
Webhook Triggers:
Extend afterCreate()/afterUpdate() to fire webhooks:
public static function afterCreate($record): void
{
http_post('https://webhook.example.com', ['data' => $record]);
}
Rate Limiting:
Implement exponential backoff in getHttpClient():
Http::retry(3, 100)->throw();
How can I help you explore Laravel packages today?