Help us understand the problem. What is going on with this article?

AxiosでAPIレスポンスをcamelCaseに変換するお話

はじめに

この記事は呉高専 Advent Calendar 2019 9日目の記事になります。

こんにちは、呉高専在学中のフロントエンドエンジニアの@kobakazu0429です。

12月も始まって1週間が経とうとしているのに、このアドベンドカレンダーはまだ1つも投稿されていなくて寂しいですね。。。
(そもそも、今のところ4記事分しか予約されていない!)

普段はReactを書いているのですが、バックエンドや、外部サービスからデータを取ってくる際には100%と言っていいほど、 GitHub - axios/axios を利用しています。
axios便利でいいですよね!
ですが、jsonのkeyは基本snake_caseだと思うので、camelCaseのjsではいまいち、と感じることもしばしば。

「各レスポンスを手作業で変換なんかしたくない!!」そんなあなたに、今回の記事がおすすめです。

Demo: https://codesandbox.io/s/funny-payne-4q345

axios#interceptorsとは

axiosにはinterceptorsという、リクエスト/レスポンスを intercept(傍受する) メソッドが生えています。
簡単にいうと、リクエスト/レスポンスの前後に処理を挟むことができます。
こちらに関しては、axiosを乗りこなす機能についての知見集#3-1-interceptorsで処理差し込み
という記事が、非常にわかりやすくまとまっているので、より詳しく知りたい方は1度目を通しておくと良いでしょう。

snake_case → camelCase変換

こちらはライブラリ選定中に、lodashのissueを見つけてしまったのでそのまま流用させていただこうと思います。

一部わかりやすように変数名を変更しています。

const mapKeysDeep = (data, callback) => {
  if (isArray(data)) {
    return data.map(innerData => mapKeysDeep(innerData, callback));
  } else if (isObject(data)) {
    return mapValues(mapKeys(data, callback), val => mapKeysDeep(val, callback))
  } else {
    return data;
  }
}
const mapKeysCamelCase = data => mapKeysDeep(data, (_value, key) => camelCase(key));

GitHub - lodash/lodash issue: Feature request - deep object walk through #1244

実装

今回はデモとしてQiitaのAPIをお借りして、私(@kobakazu0429)のuserデータを取得してみます。
Demo: https://codesandbox.io/s/funny-payne-4q345

ライブラリのインストール

$ yarn add axios
$ yarn add lodash.camelcase lodash.isarray lodash.isobject lodash.mapkeys lodash.mapvalues lodash.snakecase

# TypeScriptを使っている場合はこちらの型もご一緒に
$ yarn add -D @types/lodash.camelcase @types/lodash.isarray @types/lodash.isobject @types/lodash.mapkeys @types/lodash.mapvalues @types/lodash.snakecase

コード

const axios = require("axios");
const isArray = require("lodash.isarray");
const isObject = require("lodash.isobject");
const camelCase = require("lodash.camelcase");
const mapValues = require("lodash.mapvalues");
const mapKeys = require("lodash.mapkeys");

const mapKeysDeep = (data, callback) => {
  if (isArray(data)) {
    return data.map(innerData => mapKeysDeep(innerData, callback));
  } else if (isObject(data)) {
    return mapValues(mapKeys(data, callback), val =>
      mapKeysDeep(val, callback)
    );
  } else {
    return data;
  }
};

const mapKeysCamelCase = data =>
  mapKeysDeep(data, (_value, key) => camelCase(key));

const myAxios = axios.create({ baseURL: "https://qiita.com/api/v2/" });

// 一番重要なところ!
myAxios.interceptors.response.use(
  response => {
    const { data } = response;
    const convertedData = mapKeysCamelCase(data);
    return { ...response, data: convertedData };
  },
  error => {
    console.log(error);
    return Promise.reject(error);
  }
);

// 使い方
const res = await myAxios.get("users/kobakazu0429");

実際のレスポンス

{
    "description": null,
    "facebook_id": null,
    "followees_count": 2,
    "followers_count": 0,
    "github_login_name": "kobakazu0429",
    "id": "kobakazu0429",
    "items_count": 4,
    "linkedin_id": null,
    "location": null,
    "name": "",
    "organization": null,
    "permanent_id": 197122,
    "profile_image_url": "https://avatars1.githubusercontent.com/u/31001505?v=4",
    "team_only": false,
    "twitter_screen_name": "kobakazu0429",
    "website_url": null
}

変換後のレスポンス

{
    "description": null,
    "facebookId": null,
    "followeesCount": 2,
    "followersCount": 0,
    "githubLoginName": "kobakazu0429",
    "id": "kobakazu0429",
    "itemsCount": 4,
    "linkedinId": null,
    "location": null,
    "name": "",
    "organization": null,
    "permanentId": 197122,
    "profileImageUrl": "https://avatars1.githubusercontent.com/u/31001505?v=4",
    "teamOnly": false,
    "twitterScreenName": "kobakazu0429",
    "websiteUrl": null
}

このようにきちんとスネークケースがキャメルケースに変換されていますね!
また、今回はJSON中に配列や、オブジェクトなどが入れ子状に格納されていませんでしたが、mapKeysCamelCaseは再帰的に動作するため、全keyに対して変換をかけてくれるので安心です。

最後に

今回の記事が誰かの助けになると嬉しいです。
ちなみに、再帰はAST(抽象構文木: Abstract Syntax Tree)の世界では walk と呼ばれているらしいです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away