Search API v2 を作った話

はじめに

こんにちは、メルカリJP の Search Backend チームの otter です。

今回は、BFF的役割を担っている Search API のインターフェースを version 2 として刷新したときの課題や改善した点について紹介したいと思います。

API が持っていた課題

ご存知の方も多いと思いますが、メルカリではサービス全体としてマイクロサービスアーキテクチャによる開発を採用しています。 Search API もモノリシックな API からマイクロサービスとして切り出されたもので、iOS やAndroid などのクライアントとの後方互換性を担保するため、API のインターフェースや仕様はそのまま移行されました。 そのため、サービス面では柔軟に新たな施策に対応するのが難しかったり、システム面では各マイクロサービスで共通化されるべき、エラーハンドリングやページネーションがメルカリ内のガイドラインに沿っていないという課題がありました。また、API プロトコルがメルカリ全体で推奨されている gRPC でなく、HTTP で運用されているためシステムのパフォーマンスや開発体験にも改善点が存在しました。

Search API v2 で改善したこと

これらの課題を具体的にどう改善したのか、説明していきたいと思います。

検索結果のマルチテンプレート化

Search API v2 が必要になった大きな要因のひとつが、メルカリShops の商品をメルカリの検索結果にも表示するという施策です。 そこで私たちが考えたのは、検索結果のマルチテンプレート化です。今後、メルカリの商品でないものも検索結果に表示することができるように、検索結果の項目に種別を持たせるようにし、その種別ごとに表示する内容を変えるというものです。 また、API のリクエストパラメータとしては、今までメルカリの商品をデフォルトのデータソースとしていましたが、マルチ化するにあたってデータソースを指定するインタフェースに変更しました。

Multiple templates for search results

上記の図の検索結果では、データセットに「Mercari, Shops, Service A, Service B」が指定されており、それぞれの商品の種別のテンプレートが適用されているイメージになります。

検索UIのコンポーネント化

検索結果に表示する商品以外の各要素はクライアント側でどこにどんな条件で表示するかという情報を持っていました。しかし、それでは柔軟な変更に対応できない、古いクライントから古い要素が削除できないなどの課題があったため、UIを構成する各要素をコンポーネント化し、何行目に表示させるかなどのコンポーネントポジションを API から返すように変更しました。

Componentization of the search UI

また、Facet Filter (検索条件の絞り込み) については、それまでは複雑な API インターフェースを持つ Facet Filter 用の API をクライアントから呼んでいましたが、Search API v2 を BFF として Search API からレスポンスを返すように変更しました。

gRPC と Protocol Buffers

Search API も他マイクロサービスに提供しているエンドポイントでは、gRPC サーバと共に Protocol Buffers によるインターフェースの定義を提供していましたが、前述したとおりクライアント向けには、モノリシック API 時代のインタフェースを踏襲した、HTTP プロトコルのみをサポートしていました。 メルカリのアーキテクトチームが作成した API ガイドラインでも API プロトコルは gPRC が強く推奨されています。 gRPC についてはパフォーマンス面でのメリットが強く謳われている印象がありますが、今回のようにクライアントに提供する API としての一番の恩恵は、Protocol Buffers によるインターフェースの定義だと思います。 メルカリでは各マイクロサービスの API の Protocol Buffers の定義が一元管理されており、CI によって各言語の gRPC サーバとクライアントのソースコードが自動生成されるようになっています。 iOS、Android のエンジニアへ API のインタフェースを伝えたり、フィードバックをもらいたいときは Protocol Buffers の Pull Request を見せれば一目瞭然ですし、何よりクライアントとサーバー間で型安全性が担保されているのが嬉しいですね。

エラーハンドリングとページネーション

クライアントにとってエラーハンドリングやページネーションの仕様は最も統一して欲しい項目のひとつだと思います。 これらに関してもメルカリでは API ガイドラインに仕様が規定されていますが、基本は Google API ガイドラインの エラーハンドリングページネーション に沿ったものとなっています。 しかし、最も統一すべきもののひとつだとしても、エラーのレスポンスやページネーションの仕様はなかなか後方互換性を担保して変更できるようなものではありません。 そのため API v2 を作成する際には、このあたりの仕様を統一させることは必須となりました。

最後に

今回は、Search API のインタフェースのバージョンを上げるに至った課題感や改善した点を紹介しました。 API v2 を作成するにあたっては、今後の土台となるべきものになるので、設計フェーズにかなり時間を割きましたが、実際 API v2 を実装するフェーズではそこまで苦労することはありませんでした。それは Search API が既にマイクロサービスとして切り出されていたことが、大きな要因だと思います。 このように数年ごとにサービスをマイグレーションしたり、リプレイスすることが今の開発体験も改善するし、私のように後から引き継いだメンバーの次のリプレイスを簡単にさせることができます。メルカリではこのようなシステム要件での大規模な改修もプロジェクトとして動かせるというのも強みではないかと思います。

なお、Search Backend チームではメンバーを募集中です。 少しでも興味を持っていただいた方は、ぜひとも募集要項をご覧ください。

https://mercari.wd3.myworkdayjobs.com/ja-JP/mercari_external/job/Roppongi/Software-Engineer_JR-000000014