Как справиться с JSON, если поля не совпадают со структурой в Swift
Что проверяют
Знаете ли вы Codable дальше синтезированного декодирования и умеете ли сделать разбор устойчивым к неидеальному бэкенду. Следом обычно спрашивают, как понять, на каком поле упал декодер, и что делать с незнакомым значением enum.
Как отвечать
Разберите расхождения по видам, у каждого свой инструмент:
- другие имена ключей:
enum CodingKeys: String, CodingKeyс явными строками, а для сплошного snake_casekeyDecodingStrategy = .convertFromSnakeCase; - отсутствующие поля: для опционального свойства синтезированный код вызывает
decodeIfPresent, отсутствие ключа илиnullдаютnil. Значение по умолчанию уvarсинтезированный код не использует и бросаетkeyNotFound. Нужен свойinit(from:)сdecodeIfPresent(...) ?? defaultили property wrapper; - другая вложенность:
nestedContainer(keyedBy:forKey:)достаёт поле из вложенного объекта в плоскую модель; - другие типы: для дат есть
dateDecodingStrategy(.iso8601,.formatted,.custom), число строкой разбирают в своём инициализаторе, пробуя сначала один тип, потом другой; - незнакомые значения enum: добавьте case
unknownи свойinit(from:), иначе новый статус с бэкенда уронит разбор всего ответа; - битые элементы массива: один плохой элемент валит весь массив. Помогает обёртка, которая декодирует элементы по одному и отбрасывает ошибочные.
Полезно разделить DTO, повторяющий JSON как есть, и доменную модель: тогда странности API не расползаются по приложению.
Для диагностики ловите DecodingError по кейсам: keyNotFound, typeMismatch, valueNotFound, dataCorrupted. В каждом есть context.codingPath с точным путём к полю.
Где спотыкаются
Пишут try? на каждом поле. Это глушит и отсутствие ключа, и неверный тип: бэкенд пришлёт строку вместо числа, а приложение молча покажет пустоту.
Делают опциональными все свойства подряд. Модель перестаёт описывать контракт, и проверки на nil разъезжаются по коду.
Сочетают .convertFromSnakeCase с CodingKeys, где записан исходный ключ "image_url". Стратегия сначала переводит ключ в imageUrl, и совпадения нет. И свойство imageURL без явного ключа тоже не найдётся.