Привет, Хабр! Меня зовут Владимир, работаю в Ozon, занимаюсь фронтендом.
Сегодня мы поговорим о строительстве мостов взаимопонимания между фронтендом и бэкендом – в той части, которая связана со стилем написания переменных.
Представим ситуацию: начинается работа над сайтом, разработчики тёмной и светлой сторон встречаются обсудить насущные вопросы. Один из таких вопросов связан с передачей данных.
Бекенд отдает и принимает данные в виде:
{
user_name: "user1",
main_title: "Title",
}
Фронтенд:
{
userName: "user1",
mainTitle: "Title",
}
В итоге выбор стиля написания переменных может привести к горячему спору, а иногда и к небольшой потасовке.
В этой статье мы попробуем решить эту проблему – преобразовать все данные бэкенда в данные фронтенда и наоборот. Воспользуемся для этого JavaScript.
Надеюсь, статья будет полезна начинающим разработчикам, а остальным лишний раз напомнит о знакомых приёмах по добавлению комфорта в разработку.
Шаг 1. Преобразование строки
Нам поможет встроенная функция replace. Она умеет заменять каждое вхождение заданного регулярного выражения с помощью функции маппера, которую мы передаём вторым аргументом.
# Преобразование snake_keys строки в camelKeys:
const snakeToCamel = str => {
return str.replace(/([_][a-z])/g, letter => {
return letter
.toUpperCase()
.replace('_', '')
})
}
# Преобразование camelKeys строки в snake_keys:
const camelToSnake = str => {
return str.replace(/[A-Z]/g, letter => {
return '_' + letter.toLowerCase()
})
}
Шаг 2. Работа с объектами
# Возьмем пример с начала статьи
{
user_name: "user1",
main_title: "Title",
}
Пройдёмся по ключам объекта и заменим их с помощью уже реализованной функции snakeToCamel.
const simpleKeysTransform = value => {
return Object.entries(value).reduce((acc, [key, value]) => {
const newKey = snakeToCamel(key)
return {...acc, [newKey]: value}
}, {})
}
Давайте теперь сделаем универсальную функцию преобразования и будем принимать на вход ещё переменную, отвечающую за изначальный вид стиля ключей объекта.
const keysTransform1 = (value, isInitialSnake = true) => {
const chooseStyle = isInitialSnake ? snakeToCamel : camelToSnake
return Object.entries(value).reduce((acc, [key, value]) => {
const newKey = chooseStyle(key)
return {...acc, [newKey]: value}
}, {})
}
Шаг 3. Что делать с вложенными объектами
# Например
{
user_info: {
first_name: "User",
last_name: "Userin”
}
}
Применим рекурсию. Обернём основную логику в функцию и в ней будем проверять: является ли наше значение объектом. Если да, то будем вызывать нашу функцию снова и снова.
const keysTransform2 = (input, isInitialSnake = true) => {
const chooseStyle = isInitialSnake ? snakeToCamel : camelToSnake
const recursiveTransform = value => {
if (value && typeof value === 'object') {
return Object.entries(value).reduce((acc, [key, value]) => {
const newKey = chooseStyle(key)
const newValue = recursiveTransform(value)
return {...acc, [newKey]: newValue}
}, {})
}
return value
}
return recursiveTransform(input)
}
Шаг 4. Что делать с массивами
# Например
{
users: [
{
first_name: "user1",
phone_number: 8996923
},
{
first_name: "user2",
phone_number: 12312312
}
]
}
Всё до безобразия просто. Добавим проверку на массив и на каждый его элемент навесим нашу рекурсивную функцию.
const keysTransform = (input, isInitialSnake = true) => {
const chooseStyle = isInitialSnake ? snakeToCamel : camelToSnake
const recursiveTransform = value => {
if (Array.isArray(value)) {
return value.map(recursiveTransform)
}
if (value && typeof value === 'object') {
return Object.entries(value).reduce((acc, [key, value]) => {
const newKey = chooseStyle(key)
const newValue = recursiveTransform(value)
return {...acc, [newKey]: newValue}
}, {})
}
return value
}
return recursiveTransform(input)
}
Перемирие
Давайте посмотрим, что получилось: мы реализовали алгоритм преобразования ключей объектов из snake_keys в camelKeys и наоборот. Чуть-чуть меньше раздора между фронтендом и бэкендом – неплохо же!
Существуют и другие стили написания составных слов (PascalKeys, kebab-keys, UPPER_SNAKE_KEYS). При надобности, вы уже сами сможете с ними справиться.