こんにちは。Yahoo!広告 APIのエンジニアの並河です。
私たちはYahoo!広告をもっと効率よく運用したい!というニーズに応えるためYahoo!広告 APIを開発しています。
今回はYahoo!広告 APIを半年でリニューアルした話についてご紹介します。
Yahoo!広告 APIとは
Yahoo!広告 APIとは、Yahoo!広告のあらゆるデータを取得、更新することができる外部公開APIで、広告配信実績のレポート取得の自動化や、大量の広告の一括入稿といった操作を行うことが可能なサービスです。
このように、人手では到底扱えないような大量のデータを処理したり、業務の自動化・効率化に対するソリューションの一つとして、Yahoo!広告 APIが活用されています。また、この大量データの取得や業務の自動化に利用されるという特性上、毎日数千万のHTTPリクエストを処理しています。
そんなYahoo!広告 APIですが、2020年の2月に大きくリニューアルしました。
リニューアル前(SOAP版) | リニューアル後(OpenAPI版) | |
---|---|---|
データ形式 | XML | JSON |
インターフェース定義 | WSDL (SOAP) | OpenAPI Specification |
今回のリニューアルではインターフェース定義をWSDLからOpenAPI Specificationに変更しました。また、リクエストやレスポンスで使われるデータ形式もXMLからJSONに変更しています。
具体的にどのようにリクエストが変わったか以下に例を示します。
<!-- リニューアル前(SOAP版) -->
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://ss.yahooapis.jp/V201909/Account" xmlns:ns2="http://ss.yahooapis.jp/V201909">
<SOAP-ENV:Header>
<ns1:RequestHeader>
<ns2:license>1111-1111-1111-1111</ns2:license>
<ns2:apiAccountId>2222-2222-2222-2222</ns2:apiAccountId>
<ns2:apiAccountPassword>xxxxxxxx</ns2:apiAccountPassword>
</ns1:RequestHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:get>
<ns1:selector>
<ns1:accountIds>999999</ns1:accountIds>
<ns1:accountStatuses>SERVING</ns1:accountStatuses>
</ns1:selector>
</ns1:get>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
// リニューアル後(OpenAPI版)
{
"accountIds":[999999],
"accountStatuses":["SERVING"]
}
このリニューアルにおいて、200以上のエンドポイントを、限られた時間・リソースの中で全て移行しきり、リリース後も大きな障害なくこのミッションを乗り切ることができました。
この記事では、私たちのチームがこの大きなミッションをいかにして乗り越えたのか、またそもそもどういった問題や課題があったのかを具体的にご紹介します。
リニューアルと課題
これまでは、XMLベースのプロトコル「SOAP1.1」を採用していて、「WSDL」というインターフェース定義用のXMLをAPI仕様として外部に公開し、このWSDLに基づいてAPIを呼び出していただくという利用形態でした。
一方、世の中の外部公開APIの多くは「JSONフォーマットのREST API」という形式が主流です。そのため、API利用者側には次のような問題がありました。
- SOAP形式のAPIの開発はエンジニアの確保や仕様の理解といった面で、開発コストが比較的高い
- WSDLに対応した言語やフレームワークが少ない、開発支援ツールが古い
- WSDLではAPIの細かい機能や制限の説明を表現しにくく、別途ドキュメントを用意する運用・保守コストがかかる
そこで、これらの問題を解決するためOpenAPI(OpenAPI Specification)に移行することにしました。
エンティティ構造はそのままにXML→JSON化
移行するにあたっては、既存ユーザーの移行しやすさを重視してXML→JSONというデータ形式以外に違いがなるべく出ないようにしました。
入口部分のデータ形式が変わるだけなので、私たちのシステムもビジネスロジックをあまり変更しなくて済みます。
なお、開発言語についてはリニューアル前後ともにJavaを採用しています。
これらの方針により、双方の開発コストを最小限に抑えることができました。
また、GraphQLやgRPCなど他のAPI通信方式も検討しましたが、データ形式だけ(XML→JSON)を変えたいという要求や関連システムの制約から、OpenAPIを採用することにしました。
少ない開発リソースとミッションクリティカルなプロダクト
Yahoo!広告 APIは、冒頭で触れた通りリクエスト数が多く、金銭情報のやりとりをするAPIも多いため、少しのバグが多大な損失につながるミッションクリティカルなプロダクトです。
本来であれば、業務知識が豊富なたくさんのエンジニアでじっくり時間をかけてリニューアルに取り組みたいところですが、ビジネス戦略上、OpenAPIへの移行は初回リリースが2019年10月、全てのAPIのリリースを2019年12月までに完了させる必要がありました。移行計画がはじまったのが2019年6月ごろなので、初回リリースまでには半年ほどしか開発期間がありません。
移行を進めている間も既存のSOAPで提供しているサービスの保守・新規開発があります。
当初移行にとりかかれた2名の開発者からスモールスタートし、開発体制をスケールアウトできるように移行基盤構築・自動化などの施策を打ちました。
次章でこれらの具体的な取り組みを紹介します。
開発体制をスケールアウトするための施策
開発を本格稼働させる前に移行の流れを知るため、キャンペーンの取得APIなどの1つのエンドポイントを対象にSOAPのWSDLをベースとしてOpenAPI Specification(YAMLファイル)を書き起こしました。そこから生成されたJavaエンティティをプロトタイプのアプリケーションに組み込んでみたところ、想定通り動作することが確認できました。
しかし、この手順ではプロトタイプとしては良いですが、すべてのエンドポイントをこの手順で移行するには以下の問題がありました。
- WSDLからOpenAPI Specificationに手作業で変換するため、当然作業スピードは望めない
- 変換時にフィールドの抜け漏れ、バリデーション情報の抜け漏れなどのミスをする可能性がある
そのため、これらすべてを手作業で進めるのではなく、何か機械的な方法で解決しないと期限や品質の担保が難しいことがわかりました。
そこで、期限や品質を担保すべく、SOAP版→OpenAPI版のWebAPIアプリケーションへ機械的に移行を行えるようにSpringFoxを導入し、さらにSpringFoxの生成物をOpenAPI Specificationに変換(+α)するスクリプトを作成しました。
以下のフローがその仕組みの概要です。
(1)について、既存のSOAP版JavaソースコードにSpringFoxを導入し、Swagger Specification(JSONファイル)を生成します。しかし、この生成物には以下の点で修正が必要でした。
- (当時の)SpringFoxは最新のOpenAPI 3.0.3ではなく、古い仕様しか対応していない
- 全エンドポイントのエンティティが1ファイル(2万行以上!)にまとめられてしまい使い勝手が悪い
そこで、これらの修正を自動で行うスクリプトを(2)で導入しました。スクリプトの処理内容は以下の通りです。
- Swagger SpecificationをOpenAPI Specificationの記述に変換(Swagger 2.0からOpenAPI 3.0.3への変換)
- OpenAPI Specificationを出力する際は1エンティティ1YAMLファイルで出力(OpenAPI移行後はトップダウン形式で開発をするため、1エンティティ1YAMLファイルとしたい)
- その他OpenAPI版に移行する際の細かい調整、変換(SOAP版→OpenAPI版の移行時に細かいフィールド名の変更や階層の調整)
そしてスクリプトで変換して得られたOpenAPI Specificationをopenapi-generator generate
コマンドでJavaエンティティに変換し、OpenAPI版Javaソースコードに組み込みます。
これにより、SOAP版→OpenAPI版への移行作業の80%を機械的に行えるようになり、移行、開発工数が大幅に削減されたため、SOAP版とOpenAPI版の差分の修正と、テストに注力できる体制を作ることができました。
さらに開発体制をスケールアウトさせるにあたり
- 可能な限り、手作業ではなくスクリプトなどで機械的に変換する
- ただし、このリニューアルは作業工程を全て自動化することが目的ではないので「スクリプト化するための工数」>「手作業の工数」になるところは手作業にする
- IDEの機能を使ったほうが効率的な作業はIDEの機能をふんだんに使う(Javaのクラス名やフィールド名変更等、Java文脈にも関連する作業)
- これら3つの工程を組み合わせた(初見でも画一的に作業が実施出来る)手順書を作成する
を意識しました。
また、スクリプトに関しては、開発中にフィールド名のルールを変更しなければならない場面がありましたが、このスクリプトの変換ルールのみ修正し、再度スクリプトを流すだけで大きな工数をかけることなく柔軟に変更にも耐えられる体制を作れました。
手作業部分は、作業結果に対して検算用のスクリプトやワンライナーを作っておいて、ミスや抜け漏れがないかチェックするようにしました。
これらの施策と工夫によって、Yahoo!広告 APIのナレッジがないエンジニアでも、すぐ開発できるようになり、当初2名しかいなかったエンジニアを最終的に8名まで増員でき、短期間でスケールアウトさせることができました。
※ SOAP版からOpenAPI版への移行時の一度のみ、SOAP版Javaソースコードに対してボトムアップ形式(SpringFox)を採っていますが、今後のOpenAPI版での開発ではトップダウン形式のみで完結します。
品質の担保
アプリケーション本体の実装開発体制についてはスケールアウトできるようになりましたが、OpenAPI版アプリケーションの品質を担保する必要があります。
これまでSOAP版アプリケーションでは品質を担保するために以下の2種類のテストを実施していました。
- 単体テスト(コミット時やPR,masterマージ時に動く)
- E2Eテスト(APIをコールし、前提となるリクエストを送ると、想定されたレスポンスが返ることを確認するモノ。試験環境に対してデイリーでテスト行う) → APIの数に対しての網羅率はほぼ100%
これら2種類のテストコードも合わせてOpenAPI版に移行しました。フィールドの見直しや揺れの改善を行った部分については、そのままのコードではテストが動かないので適時手直しました。
また、OpenAPIに移行した際に権限体系や認証方式を変更したため、全APIに対して全権限を網羅するテストを追加しています。
それらのテストコードをOpenAPI版アプリケーションの開発初期段階からCI/CDツールのScrewdriverに組み込み、テスト失敗(=OpenAPI移行時の移植ミス)にすぐ気付ける体制を構築しました。
また上記の2種類のテストコードだけでは担保できない事柄については、以下のAcceptanceテストをScrewdriverに組み込みこむことで品質を担保しました。
- ロードバランサー経由でのアクセスが正しくできているか
- 通信が意図せずタイムアウトしないか
これらはいくら試験環境や開発環境で期待通りの結果を確認できていても、いざ本番環境で、となると本番固有の設定などで期待通り動かないことがまれにあります。そのままの状態でデプロイしてしまうと即事故につながるので、以下の対応をしました。
1.は、APIの疎通チェックをCDパイプラインに組み込み、OKならサービスインするようにしています。
2.は、リクエスト→レスポンスが得られるまで一定時間かかる処理が意図せずタイムアウトしないかを確認します。実際に一定時間後にレスポンスを返すようなエンドポイントをあらかじめ設けておき、そこに対して1.と同様にリクエストすることで、意図せずタイムアウトしてしまわないか? を確認しています。
これらによって、SOAP版からOpenAPI版にリニューアルしたことによる性能の劣化やアプリケーションのバグを未然に防ぐことができました。
おわりに
今回の記事では、限られた期間で品質を担保しながら開発体制をスケールアウトさせ、200ものAPIのリニューアルを見事完遂させた方法についてご紹介しました。このリニューアルを通じて私たちが学んだ「システムの移行」に関する教訓を以下にまとめます。
- 既存資産で流用できるものは活用する
- 闇雲に進めるのではなく、プロトタイピングで作業を明確にする
- 人が介入すべき部分と自動化できる部分を早い段階で分離する
- 土台部分の作業を最優先でやるようにし、実装する人の待ちがない状態をキープする
- やるべきことの中でスケールアウトできることを見極める
- 自動テストを開発初期段階からCI/CDに組み込む
リニューアルで便利になったYahoo!広告 APIをぜひご活用ください!
https://ads-developers.yahoo.co.jp/developercenter/ja/index.html
※以下に、この記事でご紹介した取り組みの簡単な時系列の情報をまとめておきます。
時期 | 工程 |
---|---|
2019/06 | 設計開始 |
2019/07 | 実装開始 |
2019/08 | 開発本格稼働 |
2019/10 | Yahoo!広告 検索広告API v0 リリース |
2019/12 | Yahoo!広告 ディスプレイ広告API v0 リリース |
2020/02 | Yahoo!広告 検索広告API, ディスプレイ広告API v1 リリース |
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました
- 中山 周
- Yahoo!広告 APIエンジニア
- 庄司 正
- Yahoo!広告 APIエンジニア