7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

呉高専Advent Calendar 2019

Day 9

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

Last updated at Posted at 2019-12-08

はじめに

この記事は呉高専 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;
}
}

```js
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 と呼ばれているらしいです。

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?