Skip to content
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
221 changes: 221 additions & 0 deletions docs-v2/content/en/api/getters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
---
title: Getters
menuTitle: Getters
category: API
position: 10
---

## Motivation

Restify already provides powerful filters and get routes with relationships. However, sometimes you might want to get some extra data for your repositories.

Let's say you have a stripe user. This is how you retrieve the stripe user information through a get request:

```php
Route::get('users/stripe-information', UserStripeController::class);

// UserStripeController.php

public function __invoke(Request $request)
{
...
}
```

The `classic` approach is good, however, it has a few limitations. Firstly, you have to manually take care of the route `middleware`, the testability for these endpoints should be done separately which is hard to maintain. And finally, the endpoint is disconnected from the repository, which makes it feel out of context so has a bad readability.

So, code readability, testability and maintainability become hard.

## Getter definition

Getters are very similar to getters. The big difference, is that getters only allow get requests, and should not perform any kind of DB data writing:

The getter is nothing more than a class, that extends the `Binaryk\LaravelRestify\Getters\Getter` abstract class.

An example of a getter class:

```php
namespace App\Restify\Getters;

use Binaryk\LaravelRestify\Getters\Getter;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;use Illuminate\Support\Collection;

class StripeInformationGetter extends Getter
{
public static $uriKey = 'stripe-information';

public function handle(Request $request): JsonResponse
{
return response()->json([
'data' => $request->user()->asStripeUser()
]);
}
}
```

### Register getter

Then add the getter instance to the repository `getters` method:

```php
// UserRepository.php

public function getters(RestifyRequest $request): array
{
return [
StripeInformationGetter::new()
];
}
```

### Authorize getter

You can authorize certain getters to be active for specific users:

```php
public function getters(RestifyRequest $request): array
{
return [
StripeInformationGetter::new()->canSee(function (Request $request) {
return $request->user()->can('seeStripeInfo),
}),
];
}
```

### Call getters

To call a getter, you simply access:

```http request
POST: api/restify/posts/getters/stripe-information
```

The `getter` query param value is the `ke-bab` form of the filter class name by default, or a custom `$uriKey` [defined in the getter](#custom-uri-key)


### Handle getter

As soon the getter is called, the handled method will be invoked with the `$request`:

```php
public function handle(Request $request)
{
//

return ok();
}
```

## Getter customizations

Getters could be easily customized.

### Custom uri key

Since your class names could change along the way, you can define a `$uriKey` property to your getters, so the frontend will use always the same `getter` query when applying an getter:

```php
class StripeInformationGetter extends Getter
{
public static $uriKey = 'stripe-information';
//...

};
```

## Getters scope

By default, any getter could be used on [index](#index-getters) as well as on [show](#show-getters). However, you can choose to instruct your getter to be displayed to a specific scope.

## Show getters

Show getters are used when you have to apply it for a single item.

### Show getter definition

The show getter definition is different in the way it receives arguments for the `handle` method.

Restify automatically resolves Eloquent models defined in the route id and passes it to the getter's handle method:

```php
public function handle(Request $request, User $user): JsonResponse
{

}

```

### Show getter registration

To register a show getter, we have to use the `->onlyOnShow()` accessor:

```php
public function getters(RestifyRequest $request)
{
return [
StripeInformationGetter::new()->onlyOnShow(),
];
}
```

### Show getter call

The post URL should include the key of the model we want Restify to resolve:

```http request
POST: api/restfiy/users/1/getters/stripe-information
```
### List show getters

To get the list of available getters only for a specific model key:

```http request
GET: api/api/restify/posts/1/getters
```

## Index getters

Index getters are used when you have to apply it for a many items.

### Index getter definition

The index getter definition is different in the way it receives arguments for the `handle` method.

```php
public function handle(Request $request): JsonResponse
{
//
}

```

### Index getter registration

To register an index getter, we have to use the `->onlyOnIndex()` accessor:

```php
public function getters(RestifyRequest $request)
{
return [
StripeInformationGetter::new()->onlyOnIndex(),
];
}
```

### Index getter call

The post URL:

```http request
POST: api/restfiy/posts/getters/stripe-information
```

### List index getters

To get the list of available getters:

```http request
GET: api/api/restify/posts/getters
```
8 changes: 8 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

// Global Search...
use Illuminate\Support\Facades\Route;

Route::get('/search', \Binaryk\LaravelRestify\Http\Controllers\GlobalSearchController::class);

Route::get('/profile', \Binaryk\LaravelRestify\Http\Controllers\ProfileController::class);
Expand All @@ -23,6 +25,12 @@
Route::post('/{repository}/{repositoryId}/action', \Binaryk\LaravelRestify\Http\Controllers\PerformRepositoryActionController::class)->name('restify.actions.repository.perform');
Route::post('/{repository}/{repositoryId}/actions', \Binaryk\LaravelRestify\Http\Controllers\PerformRepositoryActionController::class); // alias to the previous route

// Getters
Route::get('/{repository}/getters', \Binaryk\LaravelRestify\Http\Controllers\ListGettersController::class)->name('restify.getters.index');
Route::get('/{repository}/{repositoryId}/getters', \Binaryk\LaravelRestify\Http\Controllers\ListRepositoryGettersController::class)->name('restify.getters.repository.index');
Route::get('/{repository}/getters/{getter}', \Binaryk\LaravelRestify\Http\Controllers\PerformGetterController::class)->name('restify.getters.perform');
Route::get('/{repository}/{repositoryId}/getters/{getter}', \Binaryk\LaravelRestify\Http\Controllers\PerformRepositoryGetterController::class)->name('restify.getters.repository.perform');

// API CRUD
Route::get('/{repository}', \Binaryk\LaravelRestify\Http\Controllers\RepositoryIndexController::class)->name('restify.index');
Route::post('/{repository}', \Binaryk\LaravelRestify\Http\Controllers\RepositoryStoreController::class)->name('restify.store');
Expand Down
29 changes: 28 additions & 1 deletion src/Bootstrap/RoutesBoot.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Binaryk\LaravelRestify\Bootstrap;

use Binaryk\LaravelRestify\Getters\Getter;
use Binaryk\LaravelRestify\Http\Controllers\PerformGetterController;
use Binaryk\LaravelRestify\Http\Controllers\RepositoryIndexController;
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
use Binaryk\LaravelRestify\Restify;
use Illuminate\Contracts\Foundation\CachesRoutes;
use Illuminate\Foundation\Application;
Expand All @@ -24,7 +27,9 @@ public function boot(): void
'middleware' => config('restify.middleware', []),
];

$this->defaultRoutes($config)
$this
// ->registerCustomGettersPerforms($config)
->defaultRoutes($config)
->registerPrefixed($config)
->registerIndexPrefixed($config);
}
Expand Down Expand Up @@ -74,4 +79,26 @@ private function loadRoutesFrom(string $path): self

return $this;
}

// @deprecated
public function registerCustomGettersPerforms($config): self
{
collect(Restify::$repositories)
->filter(function ($repository) use ($config) {
return collect(app($repository)
->getters(app(RestifyRequest::class)))
->each(function (Getter $getter) use ($config, $repository) {
if (count($excludedMiddleware = $getter->excludedMiddleware())) {
Route::group($config, function () use ($excludedMiddleware, $repository, $getter) {
$getterKey = $getter->uriKey();

Route::get("/{repository}/getters/$getterKey", PerformGetterController::class)
->withoutMiddleware($excludedMiddleware);
});
}
});
});

return $this;
}
}
61 changes: 61 additions & 0 deletions src/Commands/GetterCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Binaryk\LaravelRestify\Commands;

use Illuminate\Console\ConfirmableTrait;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;

class GetterCommand extends GeneratorCommand
{
use ConfirmableTrait;

protected $name = 'restify:getter';

protected $description = 'Create a new getter class';

protected $type = 'Getter';

public function handle()
{
if (parent::handle() === false && ! $this->option('force')) {
return false;
}
}

/**
* Build the class with the given name.
* This method should return the file class content.
*
* @param string $name
* @return string
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function buildClass($name)
{
if (false === Str::endsWith($name, 'Getter')) {
$name .= 'Getter';
}

return parent::buildClass($name);
}

protected function getStub()
{
return __DIR__.'/stubs/getter.stub';
}

protected function getPath($name)
{
if (false === Str::endsWith($name, 'Getter')) {
$name .= 'Getter';
}

return parent::getPath($name);
}

protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Restify\Getters';
}
}
2 changes: 1 addition & 1 deletion src/Commands/stubs/action.stub
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ class DummyClass extends Action
{
public function handle(ActionRequest $request, Collection $models): JsonResponse
{
return $this->response()->respond();
return ok();
}
}
16 changes: 16 additions & 0 deletions src/Commands/stubs/getter.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace DummyNamespace;

use Binaryk\LaravelRestify\Getters\Getter;
use Binaryk\LaravelRestify\Http\Requests\GetterRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;

class DummyClass extends Getter
{
public function handle(GetterRequest $request): JsonResponse
{
return ok();
}
}
Loading