Flujo de nombres API
API Request & Response Case Converter
Mantén camelCase dentro de la aplicación y traduce JSON snake_case en la frontera request/response. Prueba ambas direcciones y copia un patrón con Fetch o Axios.
Respuesta: snake_case → camelCase · Solicitud: camelCase → snake_case
Dirección del límite API
{
"userProfile": {
"firstName": "Ada",
"createdAt": "2026-09-12"
}
}Generar código para el límite API
Elige un patrón de cliente HTTP JSON. El ejemplo convierte objetos salientes a snake_case y respuestas JSON entrantes a camelCase.
type JsonRecord = Record<string, unknown>
function isJsonObject(value: unknown): value is JsonRecord {
if (value === null || typeof value !== "object" || Array.isArray(value)) {
return false
}
return Object.getPrototypeOf(value) === Object.prototype
}
function splitPrefix(key: string) {
const prefix = key.match(/^[_$]+/u)?.[0] ?? ""
return { prefix, value: key.slice(prefix.length) }
}
function splitWords(value: string) {
return value
.replace(/([A-Z]+)([A-Z][a-z])/gu, "$1 $2")
.replace(/([a-z0-9])([A-Z])/gu, "$1 $2")
.split(/[^A-Za-z0-9]+/u)
.filter(Boolean)
}
function toCamelKey(key: string) {
const { prefix, value } = splitPrefix(key)
const words = splitWords(value).map((word) => word.toLowerCase())
const [firstWord, ...restWords] = words
if (!firstWord) return key
return prefix + firstWord + restWords
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join("")
}
function toSnakeKey(key: string) {
const { prefix, value } = splitPrefix(key)
const words = splitWords(value).map((word) => word.toLowerCase())
return words.length ? prefix + words.join("_") : key
}
function mapJsonKeys(
value: unknown,
convertKey: (key: string) => string,
): unknown {
if (Array.isArray(value)) {
return value.map((item) => mapJsonKeys(item, convertKey))
}
if (!isJsonObject(value)) {
return value
}
const output: JsonRecord = {}
for (const [key, child] of Object.entries(value)) {
const nextKey = convertKey(key)
if (Object.hasOwn(output, nextKey)) {
throw new Error(`Key collision after case conversion: ${nextKey}`)
}
output[nextKey] = mapJsonKeys(child, convertKey)
}
return output
}
export function keysToCamel(value: unknown) {
return mapJsonKeys(value, toCamelKey)
}
export function keysToSnake(value: unknown) {
return mapJsonKeys(value, toSnakeKey)
}
export async function apiJson<T>(
url: string,
options: { method?: string; body?: unknown } = {},
): Promise<T> {
const response = await fetch(url, {
method: options.method ?? (options.body === undefined ? "GET" : "POST"),
headers: { "content-type": "application/json" },
body:
options.body === undefined
? undefined
: JSON.stringify(keysToSnake(options.body)),
})
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`)
}
const wireData: unknown = await response.json()
return keysToCamel(wireData) as T
}Este límite está pensado para payloads JSON. Mantén FormData, Blob, streams, archivos y otros cuerpos no JSON fuera del mapper.
Centraliza la conversión en el límite API
Componentes, hooks, stores y código de dominio mantienen una convención interna mientras el contrato JSON externo puede usar otra.
1. Normaliza respuestas entrantes
Después de analizar el JSON del servidor, convierte recursivamente las claves snake_case a camelCase antes de usarlas en la app.
2. Normaliza solicitudes salientes
Antes de serializar JSON, convierte las claves camelCase de la app al snake_case esperado por la API.
3. Deja fuera los cuerpos no JSON
No pases FormData, Blob, streams, archivos o instancias de clase arbitrarias por un mapper de claves JSON.
¿Necesitas stop paths, exclusiones regex, diff o archivos JSON locales?
Usa JSON Key Case Converter para reglas avanzadas de objetos y aplica la misma política en tu código.
Abrir JSON Key Case ConverterGuías de implementación API
Elige la guía del cliente HTTP, query function, serializador o capa de modelos que uses.
Fetch API
Envuelve solicitudes y respuestas JSON sin tocar cuerpos no JSON.
Axios
Usa una instancia Axios dedicada con interceptors de request/response.
TanStack Query
Coloca el mapeo en query/mutation functions compartidas, no en componentes.
Jackson
Aplica estrategias de nombres en los límites de serialización Java.
Pydantic
Usa alias de modelos para separar campos Python del JSON externo.
Diccionarios Python
Convierte recursivamente claves dict/list cuando no haya una capa de modelos.