Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Integração com o iFood: o problema na homologação do developer

2026年09月26日に「Dev.to」が公開したITニュース「Integração com o iFood: o problema na homologação do developer」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

レストラン管理SaaS「Temperô」がiFoodと連携する際、APIイベントコードの誤用、非同期処理の考慮不足、複数システムでのポーリング競合などのバグに直面した。詳細なログとドキュメント遵守、そして単一の消費者設定の重要性を学んだ。

ITニュース解説

Temperôというレストラン管理システムは、フードデリバリープラットフォームであるiFoodとの連携を自動化し、レストランの業務効率を向上させることを目指した。このシステムはNode.js、TypeScript、Express、そして生のSQLを用いたPostgreSQLを技術基盤としており、iFoodで受けた注文をTemperôのオペレーションフローに自動で取り込み、キッチンへの指示、配達、決済までを一貫して管理し、両システム間で注文状況を同期させることを目標としていた。これにより、レストランが複数のシステムを同時に操作する手間を省き、スムーズな運営を可能にする。

iFoodとの連携においては、「ポーリング」という方式が採用された。これは、Temperôが15秒ごとにiFoodのAPIに問い合わせを行い、「新しいイベント(注文やキャンセルなど)が発生していないか」を能動的に確認する仕組みである。通常、外部サービスからシステムへ直接通知される「Webhook」方式もあるが、今回はiFoodのAPIの制約により、Temperôが情報をiFoodから「取りに行く」ポーリングが唯一の選択肢だった。認証方式には、複数のレストランを単一の認証情報で管理できる「集中型」モデルを選び、APIアクセスに必要なOAuth2トークンは、有効期限が切れる前に自動で更新する「プロアクティブ」な方法と、エラー発生時に再取得する「リアクティブ」な方法の両方で管理した。連携の最初の段階では、iFoodからの「配達」注文のみを対象とし、それ以外のタイプの注文は自動で拒否するように設定された。また、iFoodのメニュー項目とTemperôの内部メニューを直接マッピングせず、iFoodからの注文データにある商品名と価格をそのまま利用する柔軟な設計を採用した。決済処理についても、人の手を介さずに自動で完結するようにシステムを構築した。

開発の過程ではいくつかの課題に直面した。一つは、iFoodから送られてくるイベントデータにcode(短いコード)とfullCode(詳細な名前)という二つの類似したフィールドがあったことだ。当初、開発者はイベントの種類をcodeフィールドで判別しようとしたが、実際のデータは期待と異なり、すべての重要なイベントが処理されずに無視されていた。この問題は、システムのログに残された生データを確認し、iFoodのドキュメントで「正規」とされていたfullCodeフィールドを使用するように修正することで解決した。この経験は、ドキュメントに記載された情報が最も信頼できる源であるという重要な教訓となった。また、日付を扱う際にも問題が発生した。UTC(協定世界時)とローカルタイムの変換が適切でなかったため、特に深夜に発生した注文がシステムの表示画面に現れないというバグも見つかった。このようなバグは、自動テストでは見過ごされやすく、実際に運用上の細かな状況でしか現れないため、手動による厳密な確認が重要であることを示した。

特に難航したのは、iFoodからの注文キャンセルイベントの処理であった。iFoodのAPIにキャンセルリクエストを送信すると、すぐに「リクエストを受け付けた」という応答(HTTPステータスコード202 Accepted)が返ってくる。しかし、これはキャンセルが実際に完了したことを意味するものではなく、本当のキャンセル完了は、後から別のイベントとして非同期にTemperôに通知される仕組みだった。初期の実装では、キャンセルリクエストを送信した直後に、Temperô内部で注文を「キャンセル済み」としてマークしていたため、iFood側でまだキャンセルが完了していない状況と、システム内部の状態が食い違うことが頻繁に発生した。この問題を解決するため、データベースに「キャンセル処理中」という中間状態を新しく導入した。これにより、iFoodから「キャンセル完了」または「キャンセル失敗」のイベントが届くまで、注文の状態を正式に変更しないようにし、両システム間の状態の整合性を保つことができるようになった。

このプロジェクトで最も多くの時間と労力を要したのが、特定の状況でキャンセルイベントがiFoodから全くTemperôに届かないという問題の調査だった。当初、開発チームはiFoodのテスト環境自体の不安定性や、特定のキャンセル理由が関係しているのではないか、あるいはiFoodの紛争解決APIが絡んでいるのではないかなど、いくつかの仮説を立てて検証した。しかし、これらの仮説はいずれも、問題の根本原因を完全に説明できるものではなかった。

最終的に、この問題の真の原因は意外な場所で発見された。それは、開発環境で動いているTemperôのインスタンスと、本番環境で動いているTemperôのインスタンスが、両方とも同じiFoodのテストアカウント(マーチャントID)を使ってポーリングを行っていたためだった。iFoodのイベントキューはマーチャントIDごとに管理されており、どちらかのシステムが先にイベントをポーリングして受け取り、そのイベントの受信確認をiFoodに送ってしまうと、そのイベントはキューから完全に削除されてしまう。そのため、もしキャンセルリクエストを送った側のシステムではない別のシステムが先にキャンセル完了イベントを受け取ってしまった場合、キャンセルリクエストを送ったシステムは、永遠にその確認イベントを受け取ることができなくなっていたのだ。これは、外部システムの不安定さに見えた問題が、実際には自社のシステム運用における競合の問題であったという、大きな気付きとなった。この問題の解決策として、特定のiFoodアカウントからのポーリングは本番環境のシステムのみが行うようにし、開発環境はテスト用のイベントをポーリングしないように変更した。これにより、「一つの外部イベントキューに対しては、常に一つの消費者(システムインスタンス)のみがアクセスする」という厳格なルールを確立した。

iFoodへの正式な連携申請である「 homologation(承認プロセス)」では、具体的な理由が不明なまま、自動評価システムから「ログの取得エラー」のような一般的なメッセージで何度か却下された。しかし、プロジェクトの初期段階からすべてのHTTP通信とiFoodからのイベントを、詳細な情報を含む「構造化ログ」として記録していたことが、この困難を乗り越える鍵となった。構造化ログとは、APIの呼び出しパス、メソッド、対象となる店舗IDや注文ID、HTTPの応答ステータス、エラーコード、そして受け取ったイベントのデータ本体など、詳細な情報を時刻と共にプログラムが解析しやすい形式で記録したものだ。この詳細なログがあったおかげで、自分たちのシステムが問題なく動作していることをiFood側に具体的に証明し、手動での再評価を依頼することができた。外部システムとの非同期な連携においては、自分たちでコントロールできない部分が多いからこそ、このような構造化ログが「唯一の真実の源」として極めて重要であることを強く認識させられた。

このプロジェクトを通じて、外部のマーケットプレイスと連携する際に学ぶべきいくつかの重要な教訓が得られた。まず、常に外部サービスのドキュメントに記載された「正規の」フィールドと自社のシステムが扱う値を比較し、安易に見た目だけで判断しないこと。次に、APIからの「受け付けました」(202 Acceptedなど)という応答は、処理が完了したことを意味するものではないため、非同期処理においては「処理中」のような中間状態を明示的にシステム内部で管理することが不可欠であること。そして最も重要なのは、外部の共有されるイベントキューに対しては、複数のシステムインスタンスが同時にアクセスしないよう、消費者を一つに絞ることだ。複数のシステムが同じ外部キューを競合して読み取ると、あたかも外部サービスが不安定であるかのような誤解を生むが、その原因は自分たちのシステム設計上の問題である場合がほとんどだということを理解する必要がある。

関連コンテンツ

関連IT用語