Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@kobakazu0429

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

More than 1 year has passed since last update.

はじめに

この記事は呉高専 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 と呼ばれているらしいです。

2
Help us understand the problem. What is going on with this article?
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

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?