JavaScript Tips | 配列ユーティリティ:API レスポンス整形

JavaScript JavaScript
スポンサーリンク

テーマの整理:「API レスポンス整形」とは何か

「API レスポンス整形」は、外部 API から返ってきた“生のレスポンス”を、アプリ側で扱いやすい配列・オブジェクトの形に変換するユーティリティのことです。 業務だと、次のような「めんどくさい現実」がよくあります。

  • 単体オブジェクトのときもあれば、配列のときもある
  • フィールド名がバラバラ(user_iduserId など)
  • ネストが深くて、欲しい情報が取り出しづらい
  • 余計なフィールドが多くて、画面やロジックには不要

API レスポンス整形ユーティリティは、これらを一度“入口”で整えてしまい、 「アプリ内部では、いつも同じ形の配列として扱えるようにする」ための道具です。

基本コンセプト:「API の都合」から「自分たちの都合の形」に変える

よくある“扱いづらい”レスポンス例

例えば、こんなレスポンスが来るとします。

const apiResponse = {
  status: "ok",
  data: {
    users: [
      { user_id: "1", user_name: "Alice", age: "20" },
      { user_id: "2", user_name: "Bob",   age: null },
    ],
  },
  meta: {
    total: 2,
  },
};
JavaScript

アプリ側では、次のように扱いたくなります。

  • id, name, age というフィールド名にしたい
  • age は数値にしたい(null は 0 にしたいなど)
  • data.users というネストを意識したくない

この「API の形」から「アプリの形」に変える処理を、 毎回手書きするのではなく、ユーティリティとしてまとめておくのがポイントです。

ユーティリティ 1:配列化+フィールド名変換+型変換をまとめて行う

ステップの分解

やりたいことはだいたい次の 3 つです。

  • 必ず「配列」にする(単体オブジェクトでも配列に包む)
  • フィールド名を自分たちの命名規則に揃える
  • 型を揃える(文字列 → 数値、文字列 → 真偽値など)

これを一つの流れにまとめたユーティリティを作ります。

toArray ユーティリティ(おさらい)

まず、「配列か単体か分からないもの」を配列に揃える小さなユーティリティです。

function toArray(value) {
  if (value == null) return [];
  if (Array.isArray(value)) return value;
  return [value];
}
JavaScript

フィールド名変換用のマッピング

API のフィールド名と、アプリ側で使いたいフィールド名の対応を定義します。

const userFieldMap = {
  user_id: "id",
  user_name: "name",
  age: "age",
};
JavaScript

型変換ルール

前にやった「型変換一括」と同じ考え方で、フィールドごとの型変換ルールを持ちます。

const userTypeMap = {
  id:  (v) => Number(v),
  age: (v) => (v == null ? 0 : Number(v)),
};
JavaScript

実装:reshapeUsersResponse

これらを組み合わせて、「API レスポンス整形」ユーティリティを作ります。

function reshapeUsersResponse(apiResponse) {
  const rawUsers = apiResponse?.data?.users ?? [];

  const usersArray = toArray(rawUsers);

  const normalized = usersArray.map((raw) => {
    const obj = {};

    for (const apiKey in userFieldMap) {
      const appKey = userFieldMap[apiKey];
      obj[appKey] = raw[apiKey];
    }

    for (const key in userTypeMap) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        const fn = userTypeMap[key];
        obj[key] = fn(obj[key]);
      }
    }

    return obj;
  });

  return normalized;
}
JavaScript

重要ポイントの深掘り

ネストをここで“ほどく” apiResponse?.data?.users ?? [] で、 API のネスト構造をここで一度だけ意識し、 以降のコードでは「usersArray」というフラットな配列として扱えるようにしています。

フィールド名変換を一箇所に集約する userFieldMap を使って、API のキーからアプリのキーへ変換しています。 仕様変更(API 側のフィールド名変更)があっても、このマップを直せば済むようにしておくのが大事です。

型変換を“入口”で済ませる userTypeMap を使って、id や age を数値に変換しています。 これをレスポンス整形の中でやっておくと、 アプリ内部では「id は必ず数値」「age は必ず数値」という前提で書けるようになります。

例題 1:API レスポンスを整形して「扱いやすい配列」にする

const apiResponse = {
  status: "ok",
  data: {
    users: [
      { user_id: "1", user_name: "Alice", age: "20" },
      { user_id: "2", user_name: "Bob",   age: null },
    ],
  },
  meta: {
    total: 2,
  },
};

const users = reshapeUsersResponse(apiResponse);

console.log(users);
JavaScript

出力イメージはこうなります。

[
  { id: 1, name: "Alice", age: 20 },
  { id: 2, name: "Bob",   age: 0  },
]
JavaScript

ここでのポイントは、

  • ネストがほどけて、単純な配列になっている
  • フィールド名が id, name, age に揃っている
  • age が数値になっていて、null は 0 に変換されている

というところです。

この形になっていれば、 画面表示・バリデーション・サマリー生成・統計情報生成など、 これまで作ってきたユーティリティをそのまま使えます。

ユーティリティ 2:レスポンスの「成功・失敗」を一緒に扱う

シナリオ

API が失敗したときは、 「配列」ではなく「エラー情報」を返したい。

実装:safeReshapeUsersResponse

function safeReshapeUsersResponse(apiResponse) {
  if (!apiResponse || apiResponse.status !== "ok") {
    return {
      ok: false,
      error: apiResponse?.error ?? "API 呼び出しに失敗しました",
      users: [],
    };
  }

  const users = reshapeUsersResponse(apiResponse);

  return {
    ok: true,
    error: null,
    users,
  };
}
JavaScript

重要ポイントの深掘り

レスポンス整形と「成功判定」をセットにする 呼び出し側は、 result.ok を見て成功かどうかを判断し、 成功なら result.users を使う、 失敗なら result.error を表示する、 というシンプルな書き方ができます。

失敗時も「users は必ず配列」にしておく 失敗時でも users: [] を返しておくことで、 呼び出し側は「users は必ず配列」という前提で書けます。 この“形の一貫性”が、バグを減らすうえでかなり効いてきます。

ユーティリティ 3:レスポンス整形を「用途ごと」にまとめる

シナリオ

ユーザー API だけでなく、 売上 API、商品 API、ログ API など、複数のエンドポイントがある。

整形関数をまとめたモジュールのイメージ

例えば、こんな感じでまとめておくと分かりやすいです。

export const ApiShape = {
  users: {
    reshape: reshapeUsersResponse,
    safeReshape: safeReshapeUsersResponse,
  },
  // sales: { reshape: reshapeSalesResponse, ... },
  // products: { reshape: reshapeProductsResponse, ... },
};
JavaScript

使う側はこう書くだけになります。

const result = ApiShape.users.safeReshape(apiResponse);

if (!result.ok) {
  console.error(result.error);
} else {
  console.log(result.users);
}
JavaScript

ここでのポイントは、

  • 「API ごとの整形ロジック」を一箇所に閉じ込めている
  • 画面側のコードは「どの API を使うか」だけを意識すればよい

という状態を作っていることです。

API レスポンス整形ユーティリティで意識してほしい重要ポイント

「API の形を、そのままアプリに広げない」

一番大事なのは、 「API のレスポンス構造を、そのままアプリ全体に広げない」という考え方です。

API の都合で、

  • フィールド名が変わる
  • ネスト構造が変わる
  • 型が変わる

といったことは、普通に起こります。

それをアプリ全体に直結させてしまうと、 変更のたびに画面・ロジック・テストが全部壊れます。

レスポンス整形ユーティリティを“防波堤”として置いておくことで、 API の変更は「整形ユーティリティを直すだけ」で済むようになります。

「入口で整形して、内部では“自分たちの形”だけを使う」

API からデータが入ってきた瞬間に、

  • 配列化
  • フィールド名変換
  • 型変換

を済ませてしまい、 それ以降のコードは「整形済みの配列」だけを前提に書く。

この構造にしておくと、

  • バリデーション
  • サマリー生成
  • 統計情報生成
  • 可視化用変換

など、他のユーティリティがすべて「同じ形」を前提に動けるようになります。

手を動かして「API レスポンス整形」の感覚をつかむ

次のコードを実行して、

  • 生レスポンス
  • 整形済み配列
  • 成功・失敗の扱い

を体感してみてください。

function toArray(value) {
  if (value == null) return [];
  if (Array.isArray(value)) return value;
  return [value];
}

const userFieldMap = {
  user_id: "id",
  user_name: "name",
  age: "age",
};

const userTypeMap = {
  id:  (v) => Number(v),
  age: (v) => (v == null ? 0 : Number(v)),
};

function reshapeUsersResponse(apiResponse) {
  const rawUsers = apiResponse?.data?.users ?? [];
  const usersArray = toArray(rawUsers);

  const normalized = usersArray.map((raw) => {
    const obj = {};

    for (const apiKey in userFieldMap) {
      const appKey = userFieldMap[apiKey];
      obj[appKey] = raw[apiKey];
    }

    for (const key in userTypeMap) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        const fn = userTypeMap[key];
        obj[key] = fn(obj[key]);
      }
    }

    return obj;
  });

  return normalized;
}

function safeReshapeUsersResponse(apiResponse) {
  if (!apiResponse || apiResponse.status !== "ok") {
    return {
      ok: false,
      error: apiResponse?.error ?? "API 呼び出しに失敗しました",
      users: [],
    };
  }

  const users = reshapeUsersResponse(apiResponse);

  return {
    ok: true,
    error: null,
    users,
  };
}

function demo() {
  const okResponse = {
    status: "ok",
    data: {
      users: [
        { user_id: "1", user_name: "Alice", age: "20" },
        { user_id: "2", user_name: "Bob",   age: null },
      ],
    },
  };

  const ngResponse = {
    status: "error",
    error: "認証エラー",
  };

  console.log("=== OK ===");
  console.log(safeReshapeUsersResponse(okResponse));

  console.log("=== NG ===");
  console.log(safeReshapeUsersResponse(ngResponse));
}

demo();
JavaScript

まとめ:API レスポンス整形ユーティリティで「外の世界の都合を、内側でうまく受け止める」

API レスポンス整形は、 「外部サービスの都合で決まるレスポンス構造を、アプリ内部で扱いやすい配列・オブジェクトに変換するためのユーティリティ」です。

プロジェクトでは、例えばこうまとめておくとよいです。

export const ApiShape = {
  users: {
    reshape: reshapeUsersResponse,
    safeReshape: safeReshapeUsersResponse,
  },
  // 他のエンドポイントも同様に…
};
JavaScript

そして、

  • API 呼び出し直後
  • ストアに保存する直前
  • 画面に渡す直前

など、「外からデータが入ってくる入口」で必ずこの整形を通す。

そうすると、 アプリ内部は「自分たちの都合の形」だけを意識すればよくなり、 コードが一気に読みやすく・壊れにくくなります。

外の世界は変わる。 だからこそ、入口で“受け止め方”を決めておく——それが API レスポンス整形ユーティリティです。

タイトルとURLをコピーしました