Laravel + PassportでAPIを作成する

### Making an API with Laravel + Passport



以前の投稿を読んでいる場合は、Laravelプロジェクトのセットアップ方法を既に知っているので、それから続けて、パスポートをインストールしてJWT APIを作成します

If you have followed my previous posts, you already know how to setup a Laravel project, continuing from that, we will install passport to create an JWT Api



必要条件  / Requisites:

Laravel Project

Docker

Laravel/Passport

Laravel-Shovel



laravelプロジェクトフォルダー内に、一時的なdockerコンテナーを作成して「composer」を使用し、パスポートをインストールします

Inside the laravel project folder, we create a temporary docker container to use `composer`and install passport

```
docker run --rm -v $(pwd):/app composer require laravel/passport
```

この命令にはしばらく時間がかかります...完了したら、 `docker-compose`を開始できます

This instruction will take a while ...once done, we can start the `docker-compose`

```
sudo docker-compose up --build
```

実行されると、「http：// localhost /」に移動して確認できます

Once its running, we can verify by going to `http://localhost/`

新しい移行を実行し、パスポートをインストールします

We run the new migrations and Install passport

```
sudo docker-compose exec app-server php artisan migrate
sudo docker-compose exec app-server php artisan passport:install
```

これで、お気に入りのエディター（私の場合はPHPStorm）を使用してプロジェクトを開き、 `User`モデルを編集して` HasApiTokens`特性を追加できます。

We can now open the project using our favorite editor, in my case PHPStorm, and edit the `User` model to add the `HasApiTokens` trait.

```
<?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];
```

次に、 `passport：routes`を` AuthServiceProvider`に追加します

Next we add the `passport:routes` to the `AuthServiceProvider`

```
<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        Passport::routes();
        //
    }
}

```

`config \ auth.php`でApi認証プロバイダーをパスポートに変更します

We change the Api Auth provider to passport in the `config\auth.php`

```
'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
            'hash' => false,
        ],
    ],
```

次に、 `AuthController`を作成します

Now we create our `AuthController`

```
docker-compose exec app-server php artisan make:controller API\\AuthController
```

この新しいコントローラーはdockerによって作成されたため、ファイルの書き込み許可を変更する必要がある場合があります

Since this new controller was made by docker, you might need to change the write permission of the file

```
sudo chown -R myUser:myUser mylaravelproject/
```

エディターで新しいAuthControllerを開くことができます。関数については、[itsolutionstuff.com](https://www.itsolutionstuff.com/post/laravel-6-rest-api-with-passport-tutorialexample.html)

ただし、機能に若干の変更が加えられています

Now we can open the new AuthController in our editor, as for the functions, I took the example from the [itsolutionstuff.com](https://www.itsolutionstuff.com/post/laravel-6-rest-api-with-passport-tutorialexample.html)

But with some slight changes in the functions

```
<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class AuthController extends Controller
{
    /**
     * Register api
     *
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required|confirmed',
            'password_confirmation' => 'required|same:password',
        ]);

        if($validator->fails()){
            return response()->json(["error"=>$validator->errors()],422);
        }

        $input = $request->all();
        $input['password'] = bcrypt($input['password']);
        $user = User::create($input);
        $success['token'] =  $user->createToken('MyApp')->accessToken;
        $success['name'] =  $user->name;

        return response()->json($success);
    }

    /**
     * Login api
     *
     * @return \Illuminate\Http\Response
     */
    public function login(Request $request)
    {
        if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){
            $user = Auth::user();
            $success['token'] =  $user->createToken('MyApp')-> accessToken;
            $success['name'] =  $user->name;

            return  response()->json([$success]);
        }
        else{
            return response()->json(["error"=>"Unauthorized"],422);
        }
    }
}

```

`routes \ api.php`内にルートを追加します

Add the routes inside `routes\api.php`

```
Route::post('register', 'API\AuthController@register');
Route::post('login', 'API\AuthController@login');
```



お気に入りのRESTクライアントを使用して、登録とログインをテストできます。「不眠症」を使用しています

You can test the register and login, using your favorite REST client, I'm using `insomnia`

##### http://localhost/api/register

```
{
	"name":"My Name",
	"email":"secremeail@email.com",
	"password":"securepassword",
	"password_confirmation":"securepassword"
}
```

##### http://localhost/api/login

```
{
	"email":"secremeail@email.com",
	"password":"securepassword"
}
```

これで、基本的なAPIを実装しましたが、より良い応答をするために、以下を使用します。

With this, we have implemented our basic API, but to make a better response, we use:

[laravel-shovel](https://github.com/stephenlake/laravel-shovel)

より良いAPI応答を行うためのライブラリです。

Is a library to make better API responses.

インストールする前に、 `docker-compose`を停止し、一時的な` composer`コンテナを実行します。

Before installing it, we stop `docker-compose` and run a temporary `composer` container.

```
docker run --rm -v $(pwd):/app composer require stephenlake/laravel-shovel
```

ミドルウェア内のルートをグループ化します

We group the routes inside the middleware

```
Route::group(['middleware' => ['ApiRequest',"ApiResponse"]],function (){
    Route::post('register', 'API\AuthController@register');
    Route::post('login', 'API\AuthController@login');
});
```

すべてのAuthController応答を通常の応答に変更する必要があります

We have to change all the AuthController responses to normal resposes

```
<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class AuthController extends Controller
{

    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required|confirmed',
            'password_confirmation' => 'required|same:password',
        ]);

        if($validator->fails()){
           return response()->json(["messages"=>$validator->errors()],422)
               ->withMeta("message","Validation error");
        }

        $input = $request->all();
        $input['password'] = bcrypt($input['password']);
        $user = User::create($input);
        $success['token'] =  $user->createToken('MyApp')->accessToken;
        $success['name'] =  $user->name;

        return response($success);

    }


    public function login(Request $request)
    {
        $credentials = [
            'email' => $request->email,
            'password' => $request->password
        ];

        if (auth()->attempt($credentials)) {
            $token = auth()->user()->createToken('MyApp')->accessToken;
            return response(["token"=>$token]);
        } else {
            throw new \Exception("Invalid Credentials",422);
        }
    }
}
```

また、「app / Exceptions / handler.php」を処理する例外にjson応答を追加します

Also add a json response in the expection handled `app/Exepctions/handler.php`

```
public function render($request, Exception $exception)
    {
        if($request->acceptsJson())
        {
            return response()
                ->json(["messages"=>$exception->getMessage()],500)
                ->withMeta("message","internal server error");
        }
        return parent::render($request, $exception);
    }
```

このライブラリは、メタヘッダーを追加するすべてのAPI応答を標準化します

This library will standarize all api responses adding meta headers

```
{
  "meta": {
    "code": 200,
    "status": "success",
    "message": "OK"
  },
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiMTMzYzU3NjVlZmJjYTdmODQ0NDdlMTE4ZWUyZDc1YWI5YzY0MmQ3NTE2MjIzNWM1Y2FjNDNlNjI5ZDIyMzU1MzMzMzY1M2U2Yjc2ZTJhNzIiLCJpYXQiOjE1NzcxNTQwMzcsIm5iZiI6MTU3NzE1NDAzNywiZXhwIjoxNjA4Nzc2NDM3LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.KIoArr6X69eRLDluWWgEOS5gAlLmLxtYKhMURgzsmgmLooVV6EJDHGx11gnQ7_WmagtbredLabHXeSks6DQ2A8tGeqFyrVxnCRddAySxHDxhzF0VF2wF9rn_1OduDcC3xOVdrXPj-VkxToHLyW3e6A714XSTxHgzynEKBh2JtDIRN3lCt13_1F8iD9ocGHPLBrW-XFhV4Iw2atSyL8N5qQH29wsopwWZCoTqqAN2whgfylyCTlXFAcQWe0AOJEzc39jpTudkiSXAKKFuS1hCjLYYdiuae-NJGOTutDD3CzFjYrO-Kvq3-QBX7go4uNftOVwuARsvlBuyCfPbpzCM8FVfuZCEHMv7YODCrCs2s305PvsGAsIIcKB_9_dpx0nO-lZy9_Hsn6HKAztCkLBNQponLAM10pah36xaq5c_mOwRMIltRArfDi-QuteIP4XUYXJXDV96bw2BQGNlybbOU0z7x7ocLmlP7xh4NBZFjUs5eM02U6eJykewxr8UpIkoyi6N3-ZxKKhdIWfeW6jRFe7IHlKQ2QTR1Hp33zGPlwTIW8dTe8UYo_FXdQojsFV7uxc9GUUDFimrJT3cem6JvcUEWsQtbxRv3tyyMST4P5gZpr-bANS2z6DiseuQRjHU9ZNYX9rm62GS8Wo_sNXxbfayTrFk6mBsuNn33kY1T8o"
  }
}
```