LayerX エンジニアブログ

LayerX の エンジニアブログです。

openapi-generatorを使ってOpenAPI定義ファイルからGoコードを生成する

こんにちは、バクラク事業部 バクラクビジネスカード開発チームでEMとTechLeadを担当している高江 @shnjtk です。

今回は、openapi-generator を使ってOpenAPI定義ファイル(OpenAPI Specification)からGoのコードを生成する方法と、運用時のTipsについてご紹介します。

背景

バクラク事業部では、スキーマ駆動開発によりDBやGraphQLのスキーマ定義、OpenAPI定義ファイルなどから自動生成されたコードを積極的に利用する開発スタイルが採用されています。

OpenAPIについては、これまでは go-swagger を利用していましたが、対応しているバージョンが OpenAPI v2.0 までであるため、OpenAPI v3.0 に準拠したOpenAPI定義ファイルからはコードの生成ができませんでした。 自社開発のAPIであればバージョンをOpenAPI v2にすることで対応はできますが、他社により運用されているREST APIサーバを利用する場合に、それがOpenAPI v3であればそういう訳にもいかないため、OpenAPI v3に対応したツールを調査した結果、openapi-generatorを利用することにしました。

コード生成方法

本記事では、公式サイトにて公開されている petstore.yaml を使用します。

openapi-swaggerの基本的な使い方

公式サイトにあるように、基本的な使い方は以下のようになります。ここではDockerを使用していますが、npmやHomebrewを使った方法も公式サイトに記載されていますので、そちらがよい方は公式サイトをご参照ください。

docker run --rm \
    -v $PWD:/local openapitools/openapi-generator-cli generate \
    -i /local/petstore.yaml \
    -g go \
    -o /local/out/go

-i オプションで対象となる定義ファイルを、-o オプションで出力先を指定します。 また、-g で生成するコードの言語を指定します。

パッケージ名を指定する

--additional-properties オプションでパッケージ名を指定できます。ここでは petstore パッケージとします。これにあわせて、生成されたコードの出力先も変更します。自動生成されたものであることを示すために、ディレクトリを分けたり、ファイル名を xxx.gen.go のようにするなど色々やり方はあると思いますが、弊社では /gen のようにディレクトリを分けることが多いです。

  • パッケージ名を指定した生成コマンド
docker run --rm \
    -v $PWD:/local openapitools/openapi-generator-cli generate \
    -i /local/petstore.yaml \
    -g go \
    --additional-properties packageName=petstore \
    -o /local/gen/petstore

割り当てる型を指定する

--type-mappings オプションで生成時に割り当てる型を指定できます。例えば #/components/schemas/Pet のプロパティに以下のようにnumber型のpriceを追加した場合、自動生成されたコードではfloat32になります。これをfloat64に変更したい場合は次のように指定します。

  • Pet のプロパティ (関連箇所以外は省略)
    Pet:
      properties:
        price:
          type: number
  • 型を指定した生成コマンド
docker run --rm \
    -v $PWD:/local openapitools/openapi-generator-cli generate \
    -i /local/petstore.yaml \
    -g go \
    --additional-properties packageName=petstore \
    --type-mappings number=float64 \
    -o /local/out/go

プロパティ定義で format: double のようにすればオプションを付けなくてもfloat64が割り当てられたコードを生成しますが、他社により作成されたOpenAPI定義ファイルでそのような指定がされていなかったときに一括して割り当てる場合に便利です。format指定のないintegerint64int32に割り当てる場合も同様です。

運用時のTips

コード生成コマンドをタスクランナーに記載する

弊社ではバックエンド開発においてMakefileによりコマンドを管理することが多いので、Makefileにコード生成コマンドを追加します。これにより、コード生成時のオプションの編集などもgitで管理できるようになるため、どのようなオプションをいつ付けたか・外したかを理由とともに把握できるようになります。

gen-petstore:
        docker run --rm \
                -v ${PWD}:/local openapitools/openapi-generator-cli generate \
                -i /local/petstore.yaml \
                -g go \
                --additional-properties packageName=petstore \
                --type-mappings number=float64 \
                -o /local/gen/petstore

自動生成されたコードは編集しない

これはコード生成における鉄則ですね。自動生成されたコードを編集すると、次にコードを生成したときに上書きされて失われてしまうので、自動生成されたコードは編集してはいけません。IDEによっては自動生成されたコードを編集すると警告が表示されるので、もし自分が今触っているコードが自動生成されたものか分からない場合は、このような表示を見逃さないようにしましょう。

GoLandによる自動生成コード編集時の警告表示

OpenAPI定義ファイルをgit管理の対象に含める

今の自分たちのサービスがどのAPIバージョンに従っているのかを記録するためにも、OpenAPI定義ファイルはgit管理の対象に含めるようにしましょう。 APIバージョンはOpenAPI定義ファイル中に記載されていますが、コミットログにもそのAPIバージョンを記載しておくとログを見ただけですぐに分かるようになります。

例えば、最初に開発した時点ではAPI v1.0.0だったとして、その後API v1.1.0にバージョンアップした際にそのOpenAPI定義ファイルを更新してv1.1.0としてコミットログに記録しておけば、後から対象のOpenAPI定義ファイルのログを見たときに一目で現在のバージョンが分かります。

% git log --oneline petstore.yaml
9bd88ab feat: add petstore.yaml v1.1.0
1a1234e feat: add petstore.yaml v1.0.0

OpenAPI定義ファイルを編集する場合はオリジナルとは別にファイルを作成する

APIサービスの提供元からOpenAPI定義ファイルを入手した場合は基本的には編集しない方がよいのですが、事情によりどうしても編集せざるを得ないという場合があるかもしれません。そのような場合は、オリジナルの定義ファイルと自分たちで編集したファイルをそれぞれ別ファイルとしてgitで管理することをおすすめします。理由は、例えばAPIバージョンがv1.0.0からv1.1.0に上がったときに、API v1.0.0との差分と、API v1.0.0に対して自分たちで編集した内容との差分をそれぞれ個別に確認できるようになるためです。

まとめ

openapi-generatorを使うことでOpenAPI v3.0の定義ファイルからでもGoのコードを生成できるため、特にモデルの生成に活用しています。 APIのバージョンアップに追従する際も、diffを見ながら変更内容や影響範囲を把握して作業を進められるため、自信を持って更新作業に取り組むことができます。このあたりはまた別の記事にてご紹介できればと思います。

さいごに

冒頭で挙げたように、バクラク事業部では爆速開発を実現するために、OpenAPIに限らずDBスキーマやGraphQLスキーマなどからコードを自動生成するスキーマ駆動開発を採用しています。このようなツールを活用した開発効率化や生産性の向上に興味がある方はぜひお気軽にお話しましょう!

jobs.layerx.co.jp