Что происходит
custom_fields.get_by_id на живом аккаунте возвращает объект класса CustomFieldGetByIDResponse::Problem, хотя тело — нормальное описание поля со всеми опциями. Данные не теряются: у экземпляра Problem внутри лежат и type: "select", и name: "stack", и enums. Союз выбрал не тот вариант.
Проверено на 0.6.1, ruby 4.0.6:
resp = client.custom_fields.get_by_id(921_871, entity_type: "leads")
resp.class
# => Amocrm::Models::CustomFieldGetByIDResponse::Problem
Причина
CustomFieldGetByIDResponse — союз из CustomField и Problem без дискриминатора, HTTP-статус в выборе не участвует. Побеждает первый вариант без несовпадений (lib/amocrm/internal/type/union.rb, coerce).
У CustomField несовпадения находятся: code, group_id, currency, tracking_callback, remind, chained_lists объявлены как String/Integer без nilable, а amoCRM штатно шлёт по ним null. Отсутствие ключа схеме не противоречит, явный null — противоречит. Problem совпадает по type и выигрывает.
Сокращённое реальное тело:
{"id":921871,"name":"stack","type":"select","code":null,"group_id":null,"currency":null,
"tracking_callback":null,"remind":null,"chained_lists":null,"enums":[...]}
Убрать из тела null-поля — союз выбирает CustomField.
Почему это стоит чинить в спеке
Отличить успех от ошибки по классу — единственный способ, который даёт SDK, и он не работает. Обойти можно чтением сырого поля (resp[:enums]), но тогда теряется типизация, ради которой SDK и нужен.
Масштаб: вариант Problem встречается примерно в 140 моделях гема, и всюду та же схема — два полностью опциональных варианта без дискриминатора. Любая ручка, где API отдаёт null по не-nilable полю, молча опознаётся как ошибка.
Что предлагаем
- Пометить nilable поля, по которым API штатно шлёт
null — прямая причина этого случая.
- Развести успешный ответ и ошибку так, чтобы выбор не зависел от полноты тела: дискриминатором или по HTTP-статусу.
Судя по CONTRIBUTING, код генерируется, поэтому правка — в спеке.
Как это проявилось у нас
Справочное поле программы не доезжало ни в одну сделку: код считал справочник недоступным и поле не отправлял. Ошибка молчаливая — заявка уходит, поля нет.
Что происходит
custom_fields.get_by_idна живом аккаунте возвращает объект классаCustomFieldGetByIDResponse::Problem, хотя тело — нормальное описание поля со всеми опциями. Данные не теряются: у экземпляраProblemвнутри лежат иtype: "select", иname: "stack", иenums. Союз выбрал не тот вариант.Проверено на 0.6.1, ruby 4.0.6:
Причина
CustomFieldGetByIDResponse— союз изCustomFieldиProblemбез дискриминатора, HTTP-статус в выборе не участвует. Побеждает первый вариант без несовпадений (lib/amocrm/internal/type/union.rb,coerce).У
CustomFieldнесовпадения находятся:code,group_id,currency,tracking_callback,remind,chained_listsобъявлены какString/Integerбез nilable, а amoCRM штатно шлёт по нимnull. Отсутствие ключа схеме не противоречит, явныйnull— противоречит.Problemсовпадает поtypeи выигрывает.Сокращённое реальное тело:
{"id":921871,"name":"stack","type":"select","code":null,"group_id":null,"currency":null, "tracking_callback":null,"remind":null,"chained_lists":null,"enums":[...]}Убрать из тела
null-поля — союз выбираетCustomField.Почему это стоит чинить в спеке
Отличить успех от ошибки по классу — единственный способ, который даёт SDK, и он не работает. Обойти можно чтением сырого поля (
resp[:enums]), но тогда теряется типизация, ради которой SDK и нужен.Масштаб: вариант
Problemвстречается примерно в 140 моделях гема, и всюду та же схема — два полностью опциональных варианта без дискриминатора. Любая ручка, где API отдаётnullпо не-nilable полю, молча опознаётся как ошибка.Что предлагаем
null— прямая причина этого случая.Судя по CONTRIBUTING, код генерируется, поэтому правка — в спеке.
Как это проявилось у нас
Справочное поле программы не доезжало ни в одну сделку: код считал справочник недоступным и поле не отправлял. Ошибка молчаливая — заявка уходит, поля нет.