Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat autodetect routes #14

Merged
merged 6 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 12 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,19 @@ composer require rupadana/filament-api-service
php artisan make:filament-api-service BlogResource
```

Add this code to your routes file, example in routes/api.php
From version 3.0, routes automatically registered. it will grouped as '/api/`admin`'. `admin` is panelId.

```php
...
use App\Filament\Resources\BlogResource\Api;
...

BlogApiService::routes();
```

and then you will got this routes:
So, You don't need to register the routes manually.

The routes will be :

- [GET] '/api/blogs' - Return LengthAwarePaginator
- [GET] '/api/blogs/1' - Return single resource
- [PUT] '/api/blogs/1' - Update resource
- [POST] '/api/blogs' - Create resource
- [DELETE] '/api/blogs/1' - Delete resource
- [GET] '/api/`admin`/blogs' - Return LengthAwarePaginator
- [GET] '/api/`admin`/blogs/1' - Return single resource
- [PUT] '/api/`admin`/blogs/1' - Update resource
- [POST] '/api/`admin`/blogs' - Create resource
- [DELETE] '/api/`admin`/blogs/1' - Delete resource

On CreateHandler, you need to be create your custom request validation.

Expand Down Expand Up @@ -148,15 +144,11 @@ You can edit prefix & group route name as you want, default this plugin use mode

## How to secure it?

Basically, when u register the ApiService to the `routes/api.php` you can group it using `sanctum` middleware, Whichis this is default api authentication by Laravel. [Read more](https://laravel.com/docs/10.x/sanctum) about laravel sanctum
From version 3.0, it will automatically detect routes and secure it using sanctum.

### Example
To Generate Token, you just need create it from admin panel. It will be Token Resource there.

```php
Route::middleware('auth:sanctum')->group(function() {
BlogApiService::routes();
});
```
![Image](https://res.cloudinary.com/rupadana/image/upload/v1704958748/Screenshot_2024-01-11_at_15.37.55_ncpg8n.png)

## Changelog

Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
],
"require": {
"php": "^8.1",
"laravel/framework": "^10.10",
"laravel/sanctum": "^3.2",
"filament/filament": "^3.0",
"spatie/laravel-package-tools": "^1.14.0",
"illuminate/contracts": "^10.0",
Expand Down Expand Up @@ -68,4 +70,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
26 changes: 26 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

use Filament\Facades\Filament;
use Illuminate\Support\Facades\Route;

Route::prefix('api')
->name('api.')
->middleware('auth:sanctum')
->group(function () {
$panels = Filament::getPanels();

foreach ($panels as $key => $panel) {
try {

Route::prefix($panel->getId())
->name($panel->getId().'.')
->group(function () use ($panel) {
$apiServicePlugin = $panel->getPlugin('api-service');
$apiServicePlugin->route($panel);
});

} catch (Exception $e) {
dd($e);
}
}
});
13 changes: 9 additions & 4 deletions src/ApiService.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static function getResource()
return static::$resource;
}

public static function routes()
public static function registerRoutes()
{

$slug = static::getResource()::getSlug();
Expand All @@ -43,12 +43,17 @@ public static function routes()
$name
)
->prefix(static::$groupRouteName ?? $slug)
->group(function (Router $router) {
static::allRoutes($router);
->group(function (Router $route) {
static::handlers();

foreach (static::handlers() as $key => $handler) {
app($handler)->route($route);
}
});
}

public static function allRoutes(Router $router)
public static function handlers(): array
{
return [];
}
}
53 changes: 51 additions & 2 deletions src/ApiServicePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,73 @@

namespace Rupadana\ApiService;

use Exception;
use Filament\Contracts\Plugin;
use Filament\Panel;
use Filament\Support\Commands\Concerns\CanManipulateFiles;
use Rupadana\ApiService\Resources\TokenResource;

class ApiServicePlugin implements Plugin
{
use CanManipulateFiles;

public function getId(): string
{
return 'api-service';
}

public function register(Panel $panel): void
{
//
$panel->resources([
TokenResource::class,
]);
}

public function boot(Panel $panel): void
{
//
}

public static function getAbilities(Panel $panel): array
{
$resources = $panel->getResources();

$abilities = [];
foreach ($resources as $key => $resource) {
try {

$resourceName = str($resource)->beforeLast('Resource')->explode('\\')->last();

$apiServiceClass = $resource.'\\Api\\'.$resourceName.'ApiService';

$handlers = app($apiServiceClass)->handlers();

if (count($handlers) > 0) {
$abilities[$resource] = [];
foreach ($handlers as $key => $handler) {
$abilities[$resource][$handler] = app($handler)->getAbility();
}
}
} catch (Exception $e) {
}
}

return $abilities;
}

public function route(Panel $panel): void
{
$resources = $panel->getResources();

foreach ($resources as $key => $resource) {
try {
$resourceName = str($resource)->beforeLast('Resource')->explode('\\')->last();

$apiServiceClass = $resource.'\\Api\\'.$resourceName.'ApiService';

app($apiServiceClass)->registerRoutes();
} catch (Exception $e) {
}
}
}

public static function make(): static
Expand Down
9 changes: 8 additions & 1 deletion src/ApiServiceServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use Filament\Support\Facades\FilamentAsset;
use Filament\Support\Facades\FilamentIcon;
use Illuminate\Filesystem\Filesystem;
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;
use Rupadana\ApiService\Commands\MakeApiHandlerCommand;
use Rupadana\ApiService\Commands\MakeApiServiceCommand;
use Rupadana\ApiService\Commands\MakeApiTransformerCommand;
Expand Down Expand Up @@ -34,7 +36,8 @@ public function configurePackage(Package $package): void
->publishMigrations()
->askToRunMigrations()
->askToStarRepoOnGitHub('rupadana/api-service');
});
})
->hasRoute('api');

$configFileName = $package->shortName();

Expand Down Expand Up @@ -83,6 +86,10 @@ public function packageBooted(): void
], 'api-service-stubs');
}
}

$router = app('router');
$router->aliasMiddleware('abilities', CheckAbilities::class);
$router->aliasMiddleware('ability', CheckForAnyAbility::class);
}

protected function getAssetPackageName(): ?string
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/MakeApiHandlerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public function handle(): int
]);

$this->components->info("Successfully created API Handler for {$resource}!");
$this->components->info("You can register \"Handlers\\$handlerClass::route(\$router);\" to allRoutes method on APIService");
$this->components->info("You can register \"Handlers\\$handlerClass::class\" to handlers method on APIService");

return static::SUCCESS;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/MakeApiServiceCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public function handle(): int
]);

$this->components->info("Successfully created API for {$resource}!");
$this->components->info("Add \" $apiServiceClass::routes() \" to routes/api.php");
$this->components->info("It automatically registered to '/api-service' route group");

return static::SUCCESS;
}
Expand Down
27 changes: 26 additions & 1 deletion src/Http/Handlers.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,32 @@ public static function route(Router $router)
{
$method = static::getMethod();

$router->$method(static::$uri, [static::class, 'handler']);
$router
->$method(static::$uri, [static::class, 'handler'])
->name(static::getKebabClassName())
->middleware(static::getMiddlewareAliasName().':'.static::stringifyAbility());
}

protected static function getMiddlewareAliasName()
{
return 'ability';
}

public static function getKebabClassName()
{
return str(str(static::class)->beforeLast('Handler')->explode('\\')->last())->kebab();
}

public static function stringifyAbility()
{
return implode(',', static::getAbility());
}

public static function getAbility(): array
{
return [
str(str(static::getModel())->explode('\\')->last())->kebab().':'.static::getKebabClassName(),
];
}

public static function getModel()
Expand Down
13 changes: 13 additions & 0 deletions src/Models/Token.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rupadana\ApiService\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Laravel\Sanctum\PersonalAccessToken;

class Token extends PersonalAccessToken
{
use HasFactory;

protected $table = 'personal_access_tokens';
}
Loading
Loading