booklista tech blog

booklista のエンジニアリングに関する情報を公開しています。

新規プロダクト開発でOpenAPIを導入した話

アイキャッチ

簡単な自己紹介

株式会社ブックリスタでスマートフォンアプリエンジニアをしている城と申します。

現在YOMcomaというショートマンガアプリを作っています。 投稿者さん、読者さんに向けたサービスを提供予定ですので、リリースまでどうぞ楽しみにお待ちくださいませ。

OpenAPIとは

REST APIの定義方法をまとめた仕様のことで、かつてはSwaggerという名称でした。 JSONまたはYAMLでREST API定義が可能ですが、公式のサンプルはほぼYAMLで記述されており、開発現場でもYAMLで記述していることが多い印象を受けます。

参画時の状況

YOMcomaは投稿者さん向けのWEBと読者さん向けのスマートフォンアプリ(以下アプリ)があり、それぞれがREST API(以下API)でバックエンドにアクセスする構成となっています。

私は読者さん向けのアプリとバックエンドの開発を担当させていただくことになりました。 そのため本記事ではアプリ⇄バックエンドAPIの話に焦点を合わせて書かせていただきます。

アプリ開発に必要なAPIの基本設計は済んでいて、各APIの概要がドキュメントにまとめてある状態だったのでまずは詳細を定義してしまう事にしました。 OpenAPIで定義したい旨をチームメンバーに相談し「便利そうだから使ってみよう」と快諾いただけました。

YAMLによるAPI定義

サンプル

上に貼ったのは非常に簡単な例ですが、まずはYAMLを書いていきました。 私はVisual Studio Codeで記述していましたが、拡張機能のSwagger Viewerを使えば画像右側のようなプレビューを見ながら記述できるので間違いに気が付きやすかったです。 また今回はOpenAPIが初見のチームメンバーにもレビューしていただきましたが、記法は調べればすぐわかるし直感的に分かりやすいと言っていただけました。

OpenAPI仕様でYAMLを記述する方法は調べるとたくさん情報が出てくるので書き方には触れませんが、必須項目ではないけれど重要だと感じたポイントに絞って書かせていただきます。

example

パラメータや要素に例を記述できます。

後述のモックサーバーを立てる場合に返却値として活用されます。 また各要素のフォーマットを明確にしておく事で齟齬が生まれにくいので記述しておくことをおすすめします。

operationId

各APIに明示的な命名ができます。

後述のソースコード自動生成を使う場合、各APIを実行する関数名に使われるので、プロジェクトの命名規則に準じて記述することをおすすめします。 後述のドキュメント生成を使う場合、operationIdが未指定だとパーマリンクが正しく設定されなくなってしまいます。

実は色々あるYAMLの使い道

APIの詳細をYAMLで記述し、準備はととのいました。 ここからはYOMcomaでどのようにYAMLを活用していたのか紹介させていただきます。

ドキュメント生成

ReDocでYAMLファイルをドキュメントとしてHTMLに変換しました。

具体的には、コミットやプッシュ時に任意のコマンドを自動で実行できるhuskyを使用し、pre-commit時にReDocを実行しています。 これによりYAMLを改変したらドキュメントも自動更新するようにしていました。 HTMLファイルならエディタが入っていない人でも見られますし、YAMLより直感的に理解しやすいです。 API定義が見られれば作業可能なチームメンバーには、git上にあるドキュメントのパスだけ伝えることで常に最新のAPIを参照してもらえます。

huskyでpre-commit時にHTMLを出力するためのコマンド例
npm install -g redoc-cli
npm install -D husky
npx husky-init
npx husky add .husky/pre-commit 'redoc-cli bundle [yaml path] -o [output path]' 

ソースコード自動生成

YOMcomaのバックエンドはTypeScript(NestJS)で、アプリはDart(Flutter)でそれぞれ自動生成しました。

API通信部分を自動生成することで仕様と実装に乖離が生まれず、結合試験が比較的スムーズであった事もよかったです。 またAPIに修正があった時、再度ソースコード自動生成をし直す事で修正の大部分が完了する事も大きなメリットでした。

バックエンド

Himenon/openapi-typescript-code-generatorでレスポンスのスキーマ部分のみ自動生成しました。

自動生成にはほんの少し実装が必要なので、手順はリンクをご確認ください。

アプリ

OpenAPI Generatorでソースコードを自動生成しました。

Modelクラスやシリアライズ処理、APIClientクラスを自動生成し、実装工数がかなり削減できました。 ライブラリへの対応も充実していて、YOMcomaでもFlutterのHTTPクライアントとしてメジャーなライブラリDioを使ったソースコード自動生成をしています。

コマンド例
brew install openapi-generator
openapi-generator generate -i [yaml path] -g dart-dio -o ./openapi

モックサーバーを立てる

Prismでモックサーバーを立てました。

YOMcomaではバックエンド開発よりアプリ開発が先行していました。 そのためバックエンドでスタブを返すことが難しく、モックサーバーの出番となりました。 PrismはYAMLのexampleに記述した値を返してくれるので、ノーコードでモックサーバーを立てることができました。

モックサーバー起動コマンド例
npm install -D prism
npx prism mock [yaml path] -p 8080

テスト実行する

Postmanでテスト実行しました。

バックエンドのAPI開発時はPostmanにYAMLをimportしてテスト実行していました。 エンドポイントやパラメータ名を入力する手間が省けてテスト効率がアップしました。

サンプル

ハマりポイント

今回OpenAPIを使ってハマったポイントです。

allOf

type: arrayの直下にallOfや複数のpropertyを入れているケースは、OpenAPI Generatorでうまく変換されませんでした。

これはソースコードに置き換えて考えると分かりやすいのですが、List型に指定可能なのは単一のクラスです。 少なくとも私の知る言語ではList<{int id, String name}>のようには書けないので、type: arrayの下に複数の値を入れたい場合は別途Schemeを定義する必要がありました。

サンプル

さいごに

OpenAPIで定義する時にはプレビュー機能があったり、プレビューからAPIを実行できたり、他にも便利な機能がたくさんあり、きっとこれからも増えていくのではないでしょうか。 また導入コストが高くないのも大きな魅力の1つと思っています。 現在YOMcoma開発は第2フェーズに入り、チームメンバー全員がYAMLを使ってAPIを改版しており、開発サイクルが定まってきていると感じています。

この記事の内容が、これからアプリ開発をされる方の何かしらのヒントになれば幸いです。