RORK LABEN
SDK58 — Expo SDK 58 のベータが始まりました。React Native 0.88 の RC を同梱し、ベータ期間は3〜4週間と公式に書かれています11/01 — Google Play の対象 API レベル、延長を申請した場合の配信期限は11月1日です。残り44日ですEASENV — ローカルビルドに渡したはずの秘密が、中身ではなく変数名の文字列のまま届く、という報告が長く開いたままですNEW — 推奨された移行先が、すでに停止していました。廃止表を74行突き合わせた記録ですUISCENE — iOS 27 では新しい画面ライフサイクルが必須です。SDK 57 では自分で有効にする設定で、既定になるのは 58 からですCREDIT — 「AI のエラーには消費しない」がどこまでを指すのかは、同じ修正を何度か頼んだ日の記録を取ると見えてきますSDK58 — Expo SDK 58 のベータが始まりました。React Native 0.88 の RC を同梱し、ベータ期間は3〜4週間と公式に書かれています11/01 — Google Play の対象 API レベル、延長を申請した場合の配信期限は11月1日です。残り44日ですEASENV — ローカルビルドに渡したはずの秘密が、中身ではなく変数名の文字列のまま届く、という報告が長く開いたままですNEW — 推奨された移行先が、すでに停止していました。廃止表を74行突き合わせた記録ですUISCENE — iOS 27 では新しい画面ライフサイクルが必須です。SDK 57 では自分で有効にする設定で、既定になるのは 58 からですCREDIT — 「AI のエラーには消費しない」がどこまでを指すのかは、同じ修正を何度か頼んだ日の記録を取ると見えてきます
記事一覧/開発ツール
開発ツール/2026-06-19上級

Rork アプリの API 通信を堅くする — トークン更新・再試行・冪等性の設計

Rork が生成する fetch はそのままだと、トークン切れ・電波の揺らぎ・二重送信に弱いままです。トークンの自動更新、再試行とバックオフ、冪等性キーを一つのクライアント層に集約する設計を、実装コードと運用の数値とともに整理しました。

Rork568React Native238API6認証14冪等性3

プレミアム記事

リリースしたばかりの Rork アプリで、たまに「ログインし直してください」と表示されるという報告をもらいました。再現は難しく、特定の操作で必ず出るわけでもありません。手元で粘って観察すると、しばらくアプリを放置した後の最初の操作で出やすいと分かってきました。

正体は、アクセストークンの期限切れでした。Rork が生成した fetch は、トークンを付けて送るところまでは書いてくれますが、期限が切れたときに静かに更新して送り直す、という面倒までは見てくれません。期限切れがそのまま「認証エラー」として画面に出ていたのです。

個人開発で課金や同期を伴うアプリを運用していると、通信の堅さはレビューの評価に直結します。ここでは、Rork が出した素の fetch を土台に、トークン更新・再試行・冪等性を一つのクライアント層へ集約するまでの設計を、実装コードとともに残しておきます。

生成コードの fetch が抱える弱さ

Rork が最初に吐く通信コードは、おおむね次のような形に落ち着きます。

async function getProfile() {
  const res = await fetch(`${API}/me`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  return res.json();
}

このコードには三つの弱点があります。第一に、トークンが切れても更新せず、エラーをそのまま返します。第二に、電波が一瞬切れただけの一時的な失敗でも、即座にあきらめます。第三に、送信ボタンの二度押しやタイムアウト後の再送で、同じ操作が二重に実行され得ます。これらを各画面でばらばらに対処すると、コードが散らかり、抜け漏れも生まれます。だからこそ、通信の面倒を見る層を 1 か所にまとめます。

トークンの自動更新を 1 か所に集約する

最初に解くのは、トークン切れです。サーバーが 401 を返したら、リフレッシュトークンで新しいアクセストークンを取り、元のリクエストをやり直します。

ここで落とし穴になるのが、同時多発のリクエストです。画面復帰の瞬間に複数の通信が一斉に 401 を受け取ると、それぞれが更新を走らせ、更新が何度も重なってしまいます。これを避けるため、更新中は 1 本の Promise を共有させます。

let refreshing: Promise<string> | null = null;
 
async function refreshToken(): Promise<string> {
  if (!refreshing) {
    refreshing = fetch(`${API}/auth/refresh`, {
      method: "POST",
      body: JSON.stringify({ refreshToken: store.refreshToken }),
    })
      .then((r) => r.json())
      .then((d) => {
        store.accessToken = d.accessToken;
        return d.accessToken as string;
      })
      .finally(() => {
        refreshing = null;
      });
  }
  return refreshing;        // 同時に来た呼び出しは同じ更新を待ちます
}

refreshing を共有することで、何本のリクエストが同時に 401 を受けても、実際の更新は 1 回に収まります。私の環境では、この一手だけで「ログインし直してください」の報告がほぼ止まりました。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
トークン更新を 1 か所に集約し、同時多発リクエストでも更新を 1 回に抑える実装
再試行すべきエラーの見分け方と、指数バックオフ+上限の具体的な書き方
二重送信による重複課金や重複投稿を防ぐ冪等性キーの設計
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

関連記事

開発ツール2026-07-24
同じ通信が同時に何本も飛ぶのを1本に束ねる — 参照カウント付きシングルフライト層の設計
起動直後に同じ API へ何本ものリクエストが同時に飛ぶ多重フェッチを、進行中の Promise を共有して1本に束ねる設計です。束ねる範囲を決めるキーの組み立て方、失敗した Promise を配り続けてしまう罠、呼び出し側の中断が全体を巻き込む罠、そして束ね率を数えて回帰を止めるテストまで、参照カウント付きシングルフライト層の実装を実測の通信ログとともに残します。
開発ツール2026-07-14
Rork が生成した fetch コードに、Zod の検証境界を1枚だけ挟む
Rork が生成したネットワークコードは、レスポンスの形を暗黙に信頼します。APIが変わると画面は静かに真っ白になります。生成UIとネットワークの間にZodのparse層を1枚だけ差し込み、壊れ方を予測可能にする実装を、実運用の数値とともに紹介します。
開発ツール2026-09-04
EAS の secret は「アプリに入れない」設定ではありません — 接頭辞と可視性を別々に決める
EXPO_PUBLIC_ の接頭辞は成果物に入るかを決め、EAS の可視性は誰が読めるかを決めます。二つを重ねたときに OTA 更新でだけ値が消える筋道と、出荷前に自分の手で確かめる手順をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます