laravel-openapiライブラリ ドキュメントを出力してみる vol2 リクエストボディー

# 概要

- laravel-openapiを用いてリクエストボディーを定義・設定してみる。

# 前提

- 出力されたOpenAPIドキュメントは下記の方法で正しいか確認する事ができる。
    - [Swagger Editorをローカルに落として開く](https://qiita.com/miriwo/items/93a845f03435fbbce3bd)
- 下記の内容が完了していること。
    - [laravel-openapi ドキュメントを出力してみる vol1 基本的な出力](https://qiita.com/miriwo/items/2c8dcbefdde338ce62a9)
- 下記の内容を`routes/api.php`に追記する。

    ```アプリ名ディレクトリ/routes/api.php
    Route::post('/update', [UserController::class, 'update']);
    ```

- 下記の関数をUserController.phpに追記する。

    ```アプリ名ディレクトリ/app/Http/Controllers/UserController.php
    /**
     * ユーザー情報更新
     *
     * @return void
     */
    #[OpenApi\Operation]
    public function update()
    {

    }
    ```

# 方法

1. リクエストボディーのスキーマはスキーマクラスを用いて定義する。
1. 下記コマンドを実行してUserUpdateRequestBodySchema.phpを作成する。

    ```terminal
    $ php artisan openapi:make-schema UserUpdateRequestBodySchema
    ```

1. `アプリ名ディレクトリ/app/OpenApi/Schemas`に`UserUpdateRequestBodySchema.php`が作成される。
1. 下記のようなスキーマを定義したいとする。

    ```json
    {
      "id": 1,
      "name": "ユーザー名",
      "email": "test@example.com"
    }
    ```

1. 下記のように記載することで上記のスキーマを表現する事ができる。（Reusableクラスのuseとimplementsも忘れずに）

    ```アプリ名ディレクトリ/app/OpenApi/Schemas/UserUpdateRequestBodySchema.php
    <?php
    
    namespace App\OpenApi\Schemas;
    
    use GoldSpecDigital\ObjectOrientedOAS\Contracts\SchemaContract;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\AllOf;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\AnyOf;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\Not;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\OneOf;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema;
    use Vyuldashev\LaravelOpenApi\Contracts\Reusable;
    use Vyuldashev\LaravelOpenApi\Factories\SchemaFactory;
    
    class UserUpdateRequestBodySchema extends SchemaFactory implements Reusable
    {
        /**
         * @return AllOf|OneOf|AnyOf|Not|Schema
         */
        public function build(): SchemaContract
        {
            return Schema::object('UserUpdateRequestBody')
                ->properties(
                    Schema::integer('id'),
                    Schema::string('name'),
                    Schema::string('email'),
                );
        }
    }
    ```

1. ここのキーにdiscriptionとexampleを設定することもできる。下記のように各キーを定義している部分にメソッドチェーンで記載する。

    ```アプリ名ディレクトリ/app/OpenApi/Schemas/UserUpdateRequestBodySchema.php
    <?php
    
    namespace App\OpenApi\Schemas;
    
    use GoldSpecDigital\ObjectOrientedOAS\Contracts\SchemaContract;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\AllOf;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\AnyOf;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\Not;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\OneOf;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema;
    use Vyuldashev\LaravelOpenApi\Contracts\Reusable;
    use Vyuldashev\LaravelOpenApi\Factories\SchemaFactory;
    
    class UserUpdateRequestBodySchema extends SchemaFactory implements Reusable
    {
        /**
         * @return AllOf|OneOf|AnyOf|Not|Schema
         */
        public function build(): SchemaContract
        {
            return Schema::object('UserUpdateRequestBody')
                ->properties(
                    Schema::integer('id')
                        ->description('ユーザーID')
                        ->example(1),
                    Schema::string('name')
                        ->description('ユーザー名')
                        ->example('XXX YYY'),
                    Schema::string('email')
                        ->description('ユーザーメールアドレス')
                        ->example('test@example.com'),
                );
        }
    }
    ```

1. リクエストボディーそのものはリクエストボディークラスを用いて定義しスキーマクラスを呼び出す。
1. 下記コマンドを実行してUserUpdateRequrestBody.phpを作成する。

    ```terminal
    $ php artisan openapi:make-requestBody UserUpdate
    ```

1. `アプリ名ディレクトリ/app/OpenApi/RequestBodies`に`UserUpdateRequestBody.php`が作成される。
1. 下記のように記載して先に定義したUserUpdateRequestBodySchemaクラスを呼び出す。（MediaTypeとUserUpdateRequestBodySchemaのuseも忘れずに）

    ```アプリ名ディレクトリ/app/OpenApi/RequestBodies/UserUpdateRequestSchema.php
    <?php
    
    namespace App\OpenApi\RequestBodies;
    
    use App\OpenApi\Schemas\UserUpdateRequestBodySchema;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\MediaType;
    use GoldSpecDigital\ObjectOrientedOAS\Objects\RequestBody;
    use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory;
    
    class UserUpdateRequestBody extends RequestBodyFactory
    {
        public function build(): RequestBody
        {
            return RequestBody::create()
                ->content(
                    MediaType::json()
                        ->schema(UserUpdateRequestBodySchema::ref())
                );
        }
    }
    ```

1. 下記のようにUserController.phpを記載してUserUpdateRequestBodyクラスを呼び出す。（UserUpdateRequestBodyのuseを忘れずに）

    ```アプリ名ディレクトリ/app/Http/Controllers/UserController.php
    <?php
    
    namespace App\Http\Controllers;
    
    use App\OpenApi\RequestBodies\UserUpdateRequestBody;
    use Illuminate\Http\Request;
    use Vyuldashev\LaravelOpenApi\Attributes as OpenApi;
    
    #[OpenApi\PathItem]
    class UserController extends Controller
    {
        /**
         * indexを返す関数
         *
         * @return void
         */
        #[OpenApi\Operation]
        public function index()
        {
        
        }
    
        /**
         * ユーザー情報更新
         *
         * @return void
         */
        #[OpenApi\Operation]
        #[OpenApi\RequestBody(UserUpdateRequestBody::class)]
        public function update()
        {
        
        }
    }
    ```

1. 下記コマンドを実行してOpenAPIを出力する。

    ```
    $ php artisan openapi:generate default > storage/openapi.json
    ```

1. 下記のようにJSONが出力される。リクエストボディーはschemasルートオブジェクト内に定義されてpaths内から参照されるように記載されている。

    ```json
    {
        "openapi": "3.0.2",
        "info": {
            "title": "Laravel",
            "version": "1.0.0"
        },
        "servers": [
            {
                "url": "http:\/\/localhost"
            }
        ],
        "paths": {
            "\/api\/index": {
                "get": {
                    "summary": "indexを返す関数"
                }
            },
            "\/api\/update": {
                "post": {
                    "summary": "ユーザー情報更新",
                    "requestBody": {
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/UserUpdateRequestBody"
                                }
                            }
                        }
                    }
                }
            }
        },
        "components": {
            "schemas": {
                "UserUpdateRequestBody": {
                    "type": "object",
                    "properties": {
                        "id": {
                            "description": "ユーザーID",
                            "type": "integer",
                            "example": 1
                        },
                        "name": {
                            "description": "ユーザー名",
                            "type": "string",
                            "example": "XXX YYY"
                        },
                        "email": {
                            "description": "ユーザーメールアドレス",
                            "type": "string",
                            "example": "test@example.com"
                        }
                    }
                }
            }
        }
    }
    ```

# 参考文献

- [https://vyuldashev.github.io/laravel-openapi/](https://vyuldashev.github.io/laravel-openapi/)