Wiz テックブログ

Wizは、最新のIoTやICTサービスをお客様に届ける「ITの総合商社」です。

【Laravel】L5-Swaggerを導入しつつBasic認証も設定する

f:id:hnak0210:20220124170246p:plain:w730

こんにちは、バックエンドエンジニアの中嶋です。

昨今のプロダクト開発ではOpenAPIを用いたスキーマ駆動で行うことが多くなってきました。

もちろん規模や目的によって何を導入すべきか、あるいはスプレッドシートやチャットでの共有で済ませてしまうかは検討が必要ですが、今回はその中の選択肢のひとつとして、LaravelプロジェクトへのL5-Swagger導入とBasic認証の設定について簡単に紹介したいと思います。

1. 前提

確認環境

  • Laravel 8.67
  • L5-Swagger 8.0.9

OpenAPIとSwaggerとL5-Swagger

OpenAPIは「RESTful APIの仕様を記述するフォーマット」で、
SwaggerはSmartBear社が提供する「OpenAPIを便利に扱うためのツール」の一つです。

What is OpenAPI? Swagger vs. OpenAPI | Swagger Blog

ざっくり、要は「どんなURIAPIがあってどんなリクエストとレスポンスなのかを定義したり共有できるもの」と言えましょう。

そして今回紹介するL5-Swaggerは、Swaggerの機能をLaravelプロジェクトで使えるようにしたライブラリです。

github.com

Laravelのプロジェクトの中でスキーマを定義すれば「/api/documentation」にアクセスすることで以下のようなページが生成&表示でき、APIの実行例を示したりPostmanのように実際にリクエストを送信することもできます。

f:id:hnak0210:20220124161344p:plain

2. L5-Swaggerの導入

Composerでインストールする

LaravelプロジェクトにおいてComposerでインストールします。
今回はLaravel8系を使用しています。

composer require "darkaonline/l5-swagger"

JSONスキーマを作成する

スキーマはPHPDocにアノーテーションで記述する方法とJSONファイルを直接記述する方法があります。

●アノーテーションの例

提供されているサンプルの記法に倣ってController等のPHPDocにアノーテーションを記述していきます。

/**
 * @OA\Get(
 *      path="/projects/{id}",
 *      operationId="getProjectById",
 *      tags={"Projects"},
 *      summary="Get project information",
 *      description="Returns project data",
 *      @OA\Parameter(
 *          name="id",
 *          description="Project id",
 *          required=true,
 *          in="path",
 *          @OA\Schema(
 *              type="integer"
 *          )
 *      ),
 *      @OA\Response(
 *          response=200,
 *          description="successful operation"
 *       ),
 *      @OA\Response(response=400, description="Bad request"),
 *      @OA\Response(response=404, description="Resource Not Found"),
 *      security={
 *         {
 *             "oauth2_security_example": {"write:projects", "read:projects"}
 *         }
 *     },
 * )
 */

記述し終わったら

php artisan l5-swagger:generate

を実行することでSwaggerドキュメントが生成されます。

なおドキュメント生成については.envファイルに、

L5_SWAGGER_GENERATE_ALWAYS=true

を記載すれば、ロードするたびに自動で実行してくれるように設定することもできます。

github.com

JSONの例

プロジェクトの/storage配下に/api-docs/api-docs.jsonを作成し、OpenAPI Specificationの記法にて記述していきます。

{
  "/pets": {
    "get": {
      "description": "Returns all pets from the system that the user has access to",
      "responses": {
        "200": {          
          "description": "A list of pets.",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/pet"
                }
              }
            }
          }
        }
      }
    }
  }
}

JSONで直接定義する場合は特にコマンド実行は不要です。

なおスキーマはブラウザ版のSwaggerEdditerで編集・記述したり、エラーがないかの検証をすることができます。

https://editor.swagger.io

画面で表示してみる

スキーマが作成できたら/api/documentationにアクセスします。

プロジェクトにファイルが含まれているので、ローカル環境でも検証サーバーの環境でもアクセスできるのが確認できると思います。

開発の初期段階で仮のレスポンスを返すControllerを定義してサーバーに置いておけば、フロントエンドと共有できるモックサーバーとしても使えそうですね。

3. Basic認証を設定する

作成したAPIドキュメントは便利に使えるのですが、このままでは世界中にSwaggerドキュメントを公開した状態になってしまうのでBasic認証を設定していきます。

LaravelにおいてBasic認証を設定する方法としては、

の3つになるかと思います。

標準の「auth.basicミドルウェア」はDBを使用する形式であることとフレームワークのAuthライブラリに依存してしまうこと、またBasic認証のために他の外部ライブラリに依存したくないという考えから、今回は独自ミドルウェアを作成して設定していきます。

ミドルウェアを作成

適当な分かりやすい名称でミドルウェアを作成します。

php artisan make:middleware OriginalBasicAuthMiddleware

App/Http/Meddleware配下にファイルが生成されるので、中身を実装していきます。 今回の例では実行環境によってenvファイルに定義したユーザー名とパスワードを適用するように設定しています。

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class OriginalBasicAuthMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if (config('app.env') === 'local' || config('app.env') === 'testing') {
            return $next($request);
        }

        $username = $request->getUser();
        $password = $request->getPassword();

        if ($username == config('app.basic_auth_username')
            && $password == config('app.basic_auth_password')) {
            return $next($request);
        }

        header('WWW-Authenticate: Basic realm="plase user and passwoard!"');
        header("HTTP/1.0 401 Unauthorized");
        abort(401);

        return $next($request);
    }
}

kernel.phpに追記

ミドルウェアが作成できたら、kernel.phpにも忘れずに追記して有効にしておきます。今回はルートミドルウェアとして設定します。

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'org.basic.auth' => \App\Http\Middleware\OriginalBasicAuthMiddleware::class, // 追加
    ];

ルーティング設定を変更

最後に、適用させたいルートにミドルウェアを適用させます。 これにはvendorのconfigファイルをpublishする必要があります。

php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"

/config/.phpが作成されるので、「Route Group options」の項目に作成したミドルウェアを設定します。

   〜略〜
            /*
             * Route Group options
            */
            'group_options' => [
                'middleware' => ['org.basic.auth'] // 追加
            ],
        ],
   〜略〜

アクセスしてみる

認証を設定した環境においてブラウザアクセスしてみると、きちんとBasic認証を求められるように設定できました。

f:id:hnak0210:20220124174042p:plain:w350

あとはenvファイルに設定したユーザー名とパスワードを入力すればSwaggerドキュメントを表示することができます。

まとめ

今回はLaravelにおけるL5-Swaggerの導入とBasic認証の設定方法について紹介しました。
なおスキーマの定義方法は、アノーテーションJSONかymlファイルか、Stoplightを使うか等、日々議論していたりします。

これからもフロントエンドはSPAでバックエンドはAPIを提供するという構成は多いと思いますので、 チームメンバーとも話し合いながらより良い開発手法を模索していきたいと思います。


さいごに..

Wizではみんなで良いものを楽しく作るべく、積極的にエンジニアを募集しております。

↓↓興味がある方はぜひご覧ください!

careers.012grp.co.jp