NelmioApiDocBundleでJsonSchemaファイルを活用する

NelmioApiDocBundleでJsonSchemaファイルを活用する

July 12, 2020,
tags: symfony JSON Schema NelmioApiDocBundle


このエントリーをはてなブックマークに追加

nelmio/NelmioApiDocBundleでスキーマの定義するのは結構だるいことが多いです。

@Model アノテーションとか使って簡単に定義することもできますが、最終的にJSONになるのにクラスにマッピングしてレスポンス返すのが微妙だと感じる場合もあると思います。

そこで、JsonSchema活用できないかなと思って調べたらスキーマ定義に利用することができました。
今回はその方法を書いてきます。

サンプルコードについて

今回のサンプルコードはこちらになります。 polidog/sf-nelmio-doc-json-sample

Schemaファイルを用意する

まずはスキーマファイルを作らないと話にならないので、スキーマファイルを用意します。

// public/json_schema/new.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "new projects",
  "description": "Schema of post data for creating a new project",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 10,
      "maxLength": 255
    }
  },
  "required": ["name"]
}

nelmio_api_doc.yamlでdefinitionsの設定をする

nelmio_api_docでjsonスキーマを利用するにはdefinitionsの設定が必要になります。

nelmio_api_doc:
    documentation:
        info:
            title: Smaple API
            description: This is an awesome app!
            version: 1.0.0
        definitions:
            new_project:
                $ref: 'http://127.0.0.1:8000/json_schema/new.json'
    areas: # to filter documented areas
        path_patterns:
            - ^/api(?!/doc$) # Accepts routes under /api except /api/doc

ここで問題になるのが http://127.0.0.1:8000 で指定してしまっていること。 その場合は.envでURLを設定しておくと良いかと思います。

    definitions:
        new_project:
            $ref: '%env(API_DOC_HOST)%/json_schema/new.json'

コントローラにNelmioApiDoc用の設定を記述する

@SWG\Parameter アノテーションの中に記述されている@SWG\Schema に、nelmio_api_doc.yamlで指定したdefinitionsのnew_projectを指定します。

<?php


namespace App\Controller\Api;


use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Swagger\Annotations as SWG;

/**
 * @Request("/api/new", methods={"POST"})
 */
class NewController
{
    /**
     * @SWG\Parameter(
     *     name="new",
     *     in="body",
     *     schema=@SWG\Schema(ref="#definitions/new_project")
     * )
     *
     * @SWG\Response(
     *     response=201,
     *     description="create resource."
     * )
     */
    public function __invoke(Request $request)
    {
        $name = $request->request->get('name');
        // TODO add project code.

        return new JsonResponse(['status' => 'ok']);
    }
}

ドキュメントページにアクセスする

ドキュメントページにアクセスしてみると、jsonSchemaの内容が反映されています。
デフォルトだとhttp://127.0.0.1:8000/api/doc にアクセスすると以下のように表示されます。
Parametersの部分にJSONスキーマの情報が反映されています。

バリデーションを行う(おまけ)

JSONSchemaを定義したらバリデーションをしたくなると思います。
そんなときに利用できるのが ptyhard/JsonSchemaBundleです。

ドキュメントには記載がないのですが、@SchemaFile というアノテーションがあります。
このアノテーションにファイルのパスを指定することにより、リクエストまたはレスポンス時にJsonSchemaValidationを実行します。

まずは、composer requireします。

$ composer req ptyhard/json-schema-bundle

次に config/ptyhard_json_schema.yaml を用意します。
json_schemaを配置しているディレクトリを指定してください。

ptyhard_json_schema:
    json_file_directory: '%kernel.project_dir%/public/json_schema'

最後にコントローラに @SchemaFile のアノテーションを定義します。

<?php

namespace App\Controller\Api;

use Ptyhard\JsonSchemaBundle\Annotations\SchemaFile;
use Symfony\Component\HttpFoundation\JsonResponse;
use Swagger\Annotations as SWG;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/api/new", methods={"POST"})
 */
class NewController
{
    /**
     * @SWG\Parameter(
     *     name="new",
     *     in="body",
     *     schema=@SWG\Schema(ref="#definitions/new_project")
     * )
     *
     * @SWG\Response(
     *     response=201,
     *     description="create resource."
     * )
     *
     * @SWG\Tag(name="project")
     * @SchemaFile("new.json", type={"request"})
     */
    public function __invoke(Request $request)
    {
        $name = $request->request->get('name');
        // TODO add project code.

        return new JsonResponse(['status' => 'ok']);
    }
}

これで、設定は完了です。
/api/doc から試しにバリデーションが実行されるか確認してみましょう。
キャプチャ画像で成功するリクエストと、バリデーションエラーになる実行結果を用意しました。

最後に

NelmioApiDocBundleでJsonSchemaを活用するのはフロントエンドとの親和性もあがるので良いアプローチだと思います。
ぜひ試してみてください。

そして、ptyhard/JsonSchemaBundleも使い勝手が良いのでぜひ使ってみてください。

comments powered by Disqus