JavaScript · TypeScript · API boundary

Axios snake_case ↔ camelCase

If a frontend uses camelCase while a backend uses snake_case, put naming conversion at one HTTP boundary instead of scattering property renames through the app.

By Camel Case Converter Editorial TeamPublished Sep 12, 2026Last reviewed

Build a JSON-safe recursive key mapper

function isPlainObject(value) {
  return Object.prototype.toString.call(value) === "[object Object]"
}
function toCamelKey(key) { return key.replace(/_+([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()) }
function toSnakeKey(key) { return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toLowerCase() }
function mapKeys(value, keyMapper) {
  if (Array.isArray(value)) return value.map((item) => mapKeys(item, keyMapper))
  if (!isPlainObject(value)) return value
  const output = {}
  for (const [key, child] of Object.entries(value)) {
    const nextKey = keyMapper(key)
    if (Object.hasOwn(output, nextKey)) throw new Error(`Key collision: ${nextKey}`)
    output[nextKey] = mapKeys(child, keyMapper)
  }
  return output
}

Transform plain JSON objects and arrays while leaving scalar and non-plain values alone; detect collisions before overwriting data.

Attach request and response interceptors to one Axios instance

import axios from "axios"
const api = axios.create({ baseURL: "/api" })
api.interceptors.request.use((config) => {
  if (config.data && isPlainObject(config.data)) config.data = mapKeys(config.data, toSnakeKey)
  if (config.params && isPlainObject(config.params)) config.params = mapKeys(config.params, toSnakeKey)
  return config
})
api.interceptors.response.use((response) => {
  response.data = mapKeys(response.data, toCamelKey)
  return response
})

Normalize JSON request data and params to snake_case, then normalize response.data to camelCase for application code.

Keep application code camelCase

const response = await api.post("/users", {
  displayName: "Ada Lovelace",
  profileSettings: { emailNotifications: true },
})
console.log(response.data.createdAt)

Centralizing the adapter lets UI code and TypeScript models keep one internal convention while the server uses another.

Production considerations

  • Do not recursively rewrite FormData, Blob, ArrayBuffer, streams, or class instances as JSON.
  • Use a dedicated Axios instance or explicit opt-out for endpoints that should stay untouched.
  • Do not pass headers through the same object-key mapper.
  • TypeScript types do not change runtime response keys; make sure the interceptor actually transforms data.

Test the JSON boundary online

Use the browser tool to test nested objects, arrays, excluded keys, stop paths, semantic prefixes, collision handling, and a key-only diff before you copy the same convention into an application.

Drop a .json file here or choose one from your device

Files are read only in your browser. Maximum file size: 5 MB.

Converted JSON
{
  "userProfile": {
    "firstName": "Ada",
    "createdAt": "2026-09-12"
  }
}

Parsing, file reading, formatting, and key conversion run locally in your browser. JSON input is not sent to a conversion server.