Skip to content

Commit

Permalink
fix: route list and auth scaffolding (#552)
Browse files Browse the repository at this point in the history
* fix: route list and auth scaffolding

* Fix styling

* fix: docs and routes

* fix: wi

* Fix styling

---------

Co-authored-by: binaryk <[email protected]>
  • Loading branch information
binaryk and binaryk authored Mar 26, 2023
1 parent cfe365a commit aeaa35c
Show file tree
Hide file tree
Showing 11 changed files with 366 additions and 48 deletions.
8 changes: 5 additions & 3 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@

### Features

- [ ] Adding a command that lists all Restify registered routes `php artisan restify:routes`
- [x] Adding a command that lists all Restify registered routes `php artisan restify:routes`
- [ ] UI for Restify
- [ ] Support for Laravel 10
- [ ] Custom namespace and base directory for repositories
- [x] Support for Laravel 10
- [x] Custom namespace and base directory for repositories
- [ ] Deprecate `show` and use `view` as default policy method for `show` requests
- [ ] Deprecate `store` and use `create` as default policy method for `store` requests so it's Laravel compatible
2 changes: 1 addition & 1 deletion config/restify.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

'user_verify_url' => env('FRONTEND_APP_URL').'/verify/{id}/{emailHash}',

'user_model' => \Illuminate\Foundation\Auth\User::class,
'user_model' => "\App\Models\User",
],

/*
Expand Down
53 changes: 52 additions & 1 deletion docs-v2/content/en/auth/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ Laravel Restify has the support for a facile authentication with [Laravel Sanctu

Now you can finally enjoy the auth setup (`register`, `login`, `forgot`, and `reset password`).

## Quick start

tl;dr:

If you run on Laravel 10 or higher, you can use this command that will do all the setup for you:

```shell script
php artisan restify:setup-auth
```

This command will:

- **ensures** that `Sanctum` is installed and configured as the authentication provider in the `config/restify.php` file
- **appends** the `Route::restifyAuth();` line to the `routes/api.php` file to add the authentication routes

## Prerequisites

Migrate the `users`, `password_resets` table (they already exist into a fresh Laravel app).
Expand Down Expand Up @@ -116,7 +131,7 @@ Next, add the `auth:sanctum` middleware after the `api` middleware in your confi

## Login

Let's ensure the authentication is working correctly. Create a user in the DatabaseSeeder class:
Let's ensure the authentication is working correctly. Create a user in the `DatabaseSeeder` class:

```php
// DatabaseSeeder.php
Expand Down Expand Up @@ -165,6 +180,42 @@ So you should see the response like this:
}
```

### Authorization

We will discuss the authorization in more details here [Authorization](/auth/authorization). But for now let's see a simple example.

After a successful login, you will receive an authentication token. You should include this token as a `Bearer` token in the Authorization header for your subsequent API requests using [Postman](https://learning.postman.com/docs/sending-requests/authorization/#bearer-token), axios library, or cURL.

Here's an axios example for retrieving the user's profile with the generated token:

```js
import axios from 'axios';

const token = '1|f7D1qkALtM9GKDkjREKpwMRKTZg2ZnFqDZTSe53k';

axios.get('http://restify-app.test/api/restify/profile', {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
```

Here's a cURL example for retrieving the user's profile with the generated token:
```bash
curl -X GET "http://restify-app.test/api/restify/profile" \
-H "Accept: application/json" \
-H "Authorization: Bearer 1|f7D1qkALtM9GKDkjREKpwMRKTZg2ZnFqDZTSe53k"
```

Replace `http://restify-app.test` with your actual domain and use the authentication token you received after logging in.

## Register

Let's see how to register a new user in the application. You can test the registration using Curl or Postman.
Expand Down
10 changes: 8 additions & 2 deletions docs-v2/content/en/auth/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@ Before diving into details about authorization, it is important for you to under

When you run a request (ie via Postman), it hits the Laravel application. Laravel will load every single Service Provider it has defined into `config/app.php` and [auto discovered ](https://laravel.com/docs/packages#package-discovery) providers as well.

Restify injects the `RestifyApplicationServiceProvider` in your `config/app.php` and it also has an auto discovered provider called `LaravelRestify\LaravelRestifyServiceProvider`.
Restify injects the `RestifyApplicationServiceProvider` in your `config/app.php` and it also has an auto discovered provider called `\Binaryk\LaravelRestify\LaravelRestifyServiceProvider`.

- The `LaravelRestifyServiceProvider` is booted first. This will basically push the `RestifyInjector` middleware at the end of the middleware stack.

- Then, the `RestifyApplicationServiceProvider` is booted. This will define the gate, will load repositories and make the auth routes macro. You now have full control over this provider.

- The `RestifyInjector` will be handled. It will register all the routes.

- On each request, if the requested route is a Restify route, Laravel will handle other middlewares defined in the `restify.php` -> `middleware`.
- On each request, if the requested route is a Restify route, Laravel will handle other middlewares defined in the `restify.php` -> `middleware`. Here is where you should have the `auth:sanctum` middleware to protect your API against unauthenticated users.

## Prerequisites

Before we dive into the details of authorization, we need to make sure that you have a basic understanding of how Laravel's authorization works. If you are not familiar with it, we highly recommend reading the [documentation](https://laravel.com/docs/authorization) before you move forward.

You may also visit the [Authentication/login](/auth/authentication#authorization) section to learn how to login and use the Bearer token.


## View Restify
Expand Down
22 changes: 16 additions & 6 deletions docs-v2/content/en/auth/profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,39 @@ category: Auth
position: 1
---

## Sanctum middleware
## Prerequisites

To make sure you can get your profile just right, you should add the `auth:sanctum` middleware to the restify middleware config:
Make sure you followed the [Authentication](/docs/auth/authentication) guide before, because one common mistake is that people do not add this middleware:

```php
// config/restify.php

'middleware' => [
'api',
// ...
'auth:sanctum',
\Binaryk\LaravelRestify\Http\Middleware\DispatchRestifyStartingEvent::class,
\Binaryk\LaravelRestify\Http\Middleware\AuthorizeRestify::class,
// ...
]
```

## Get profile

Before retrieving the user's profile, you need to log in and obtain an authentication token. You can refer to the [login documentation](/auth/authentication#login) for details on how to authenticate a user. Make sure to include the `Bearer {$token}` in the `Authorization` header for the subsequent API requests, either using Postman or cURL.

When retrieving the user's profile, it is serialized by using the `UserRepository`.

```http request
GET: /api/restify/profile
```

Here's an example of a cURL request for retrieving the user's profile with a random token:

```bash
curl -X GET "http://your-domain.com/api/restify/profile" \
-H "Accept: application/json" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
```

Replace `http://your-domain.com` with your actual domain and `eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...` with the authentication token you obtained after logging in.

This is what we have for a basic profile:

```json
Expand Down
70 changes: 35 additions & 35 deletions src/Bootstrap/RoutesDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,51 @@ public function __invoke(string $uriKey = null)
Route::get(
$prefix.'/filters',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryFilterController::class
);
)->name('filters.index');

// Actions
Route::get(
$prefix.'/actions',
\Binaryk\LaravelRestify\Http\Controllers\ListActionsController::class
)->name('restify.actions.index');
)->name('actions.index');
Route::get(
$prefix.'/{repositoryId}/actions',
\Binaryk\LaravelRestify\Http\Controllers\ListRepositoryActionsController::class
)->name('restify.actions.repository.index');
)->name('actions.repository.index');
Route::post(
$prefix.'/action',
\Binaryk\LaravelRestify\Http\Controllers\PerformActionController::class
)->name('restify.actions.perform');
)->name('actions.perform');
Route::post(
$prefix.'/actions',
\Binaryk\LaravelRestify\Http\Controllers\PerformActionController::class
); // alias to the previous route
)->name('actions.performs'); // alias to the previous route
Route::post(
$prefix.'/{repositoryId}/action',
\Binaryk\LaravelRestify\Http\Controllers\PerformRepositoryActionController::class
)->name('restify.actions.repository.perform');
)->name('actions.repository.perform');
Route::post(
$prefix.'/{repositoryId}/actions',
\Binaryk\LaravelRestify\Http\Controllers\PerformRepositoryActionController::class
); // alias to the previous route
)->name('actions.repository.performs'); // alias to the previous route

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

// API CRUD
Route::get(
Expand All @@ -75,39 +75,39 @@ public function __invoke(string $uriKey = null)
Route::post(
$prefix.'',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryStoreController::class
)->name('restify.store');
)->name('store');
Route::post(
$prefix.'/bulk',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryStoreBulkController::class
)->name('restify.store.bulk');
)->name('store.bulk');
Route::post(
$prefix.'/bulk/update',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryUpdateBulkController::class
)->name('restify.update.bulk');
)->name('update.bulk');
Route::delete(
$prefix.'/bulk/delete',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryDestroyBulkController::class
)->name('restify.destroy.bulk');
)->name('destroy.bulk');
Route::get(
$prefix.'/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryShowController::class
)->name('restify.show')->withoutMiddleware($this->excludedMiddleware);
)->name('show')->withoutMiddleware($this->excludedMiddleware);
Route::patch(
$prefix.'/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryPatchController::class
)->name('restify.patch');
)->name('patch');
Route::put(
$prefix.'/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryUpdateController::class
)->name('restify.put');
)->name('put');
Route::post(
$prefix.'/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryUpdateController::class
)->name('restify.update');
)->name('update');
Route::delete(
$prefix.'/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryDestroyController::class
)->name('restify.destroy');
)->name('destroy');

if ($uriKey) {
return;
Expand All @@ -117,61 +117,61 @@ public function __invoke(string $uriKey = null)
Route::delete(
$prefix.'/{repositoryId}/field/{field}',
\Binaryk\LaravelRestify\Http\Controllers\FieldDestroyController::class
);
)->name('field.destroy');

// Attach related repository id
Route::post(
$prefix.'/{repositoryId}/attach/{relatedRepository}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryAttachController::class
);
)->name('attach');
Route::post(
$prefix.'/{repositoryId}/detach/{relatedRepository}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryDetachController::class
);
)->name('detach');
Route::post(
$prefix.'/{repositoryId}/sync/{relatedRepository}',
\Binaryk\LaravelRestify\Http\Controllers\RepositorySyncController::class
);
)->name('sync');

// Relatable
Route::get(
'/{parentRepository}/{parentRepositoryId}/{repository}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryIndexController::class
);
)->name('relatable.index');
Route::post(
'/{parentRepository}/{parentRepositoryId}/{repository}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryStoreController::class
);
)->name('relatable.store');
Route::get(
'/{parentRepository}/{parentRepositoryId}/{repository}/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryShowController::class
);
)->name('relatable.show');
Route::post(
'/{parentRepository}/{parentRepositoryId}/{repository}/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryUpdateController::class
);
)->name('relatable.update');
Route::put(
'/{parentRepository}/{parentRepositoryId}/{repository}/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryUpdateController::class
);
)->name('relatable.update');
Route::delete(
'/{parentRepository}/{parentRepositoryId}/{repository}/{repositoryId}',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryDestroyController::class
);
)->name('relatable.destroy');
}

public function once(): void
{
Route::get('/search', GlobalSearchController::class);
Route::get('/search', GlobalSearchController::class)->name('search');

Route::get('/profile', ProfileController::class);
Route::put('/profile', ProfileUpdateController::class);
Route::post('/profile', ProfileUpdateController::class);
Route::get('/profile', ProfileController::class)->name('profile');
Route::put('/profile', ProfileUpdateController::class)->name('profile.updatePut');
Route::post('/profile', ProfileUpdateController::class)->name('profile.updatePost');

// RestifyJS
Route::get('/restifyjs/setup', RestifyJsSetupController::class)->withoutMiddleware(
RestifySanctumAuthenticate::class,
);
)->name('restifyjs.setup');
}

public function withoutMiddleware(...$middleware): self
Expand Down
Loading

0 comments on commit aeaa35c

Please sign in to comment.