Pull to refresh

Comments 14

Цель – показать разработчикам, с какими проблемами сталкиваются пользователи их API на примере работы с различными CRM-системами.

Возможно, я где-то переборщил со своим негодованием, но в целом я не ставил цели пожаловаться на кого-то. Даже названий CRM, на основе которых готовил статью, я не указывал…

Проблема #4 может возникнуть там, где нет необходимости/возможности в OAuth и подобном, а а AAA нужен.
Вот и появляются API с множеством шагов.
Ну и конечно не всё ограничивается взаимодействием с пользователем, когда в ход идут готовые компоненты.

Часто просто есть два разных API — первое публичное, и второе внутреннее, для сайта. Второе меняют как и когда хотят, и в нем есть больше данных.
Внутреннее апи — гибко, не спорю. Но, зачем поддерживать одновременно две апи, когда можно сделать все в рамках одной? Как правило, добавить данные в публичную апишку — проблем не составляет. А ситуаций когда нужно что-то кардинально изменить в ней, я даже как-то не встречал.
Вот тут позвольте с вами не согласиться.

А ситуаций когда нужно что-то кардинально изменить в ней, я даже как-то не встречал


Это просто «недостаток опыта»))) (прошу не воспринимать, как критику)

Два API (внутренний и внешний) — очень и очень удобная штука, которая стала уже чуть ли не стандартом де-факто в случаях, когда есть 3rd-party (сторонний) потребитель этого самого API. Подход, собственно, такой: есть внутренний API, поверх которого строится вся кухня. Это вообще логично — максимально унифицировать подход к разработке и используемый инструментарий. И есть API внешний, доступный 3-й стороне, клиентам, потребителям и т.д. и т.п., который выглядит как своеобразная обертка над внутренним API.

Такой подход позволяет решить целую уйму проблем, таких как:

1. Релизный цикл. Внутренний АПИ имеет склонность к частым изменениям, на то он и внутренний, чтобы максимально быстро меняться в угоду скорости разработки зависящих от него компонент системы и частоты релизов. Логично предположить, что он изменяется часто, итеративно, временами даже спорадически, и не требует поддержки легаси-методов (при условии, что потребители внутреннего АПИ контролируются целиком вами). Т.е. наиболее подходящая модель релизов — роллинг. При этом роллинг-релиз модель во внешнем АПИ, поставляемом третьим лицам… Ну, такое себе. Надо иметь железобетонную уверенность, что эти третьи лица — люди уравновешенные, спокойные, флегматичные, не склонные к насилию, и, что важно, быть твердо уверенным, что у них нет вашего домашнего адреса. Внешнее АПИ должно а) никогда не ломаться, б) релизиться строго версионно с заявленным уровнем поддержки обратной совместимости, в) релизиться в предсказуемые сроки, г) должно быть строго аккуратно документировано в соответствии с версией (с поддержкой архива документации на поддерживаемые версии), д) иметь поддержку нескольких параллельных версий.

2. Декомпозиция тестирования. При наличии 2 АПИ вы имеете очевидный business-critical слой логики, который необходимо покрыть спецификациями и тестировать в соответствии с оными. Т.е. во внутреннем АПИ вы можете запилить метод, который при сложении двух чисел 2+2 будет возвращать 5 — это ваше право. Но ровно до тех пор, пока метод-обертка во внешнем АПИ возвращает 4. Суть разницы — во внутреннем АПИ костыли иметь можно, и они неизбежно появятся. Во внешнем — нельзя.

3. Безопасность. Безопасность, она, как говорится, превыше всего. Честно говоря, сама идея отдать наружу целиком АПИ, возвращающий, допустим, список банковских проводок клиента по переданному в запросе айдишнику и рулить доступом на уровне авторизации и ACL-ей всяких — мне лично идея очень не нравится. Внешний АПИ, имхо, должен иметь метод «покажи мне мой список проводок», который будет гарантированно фильтровать выдачу внутреннего по айдишнику/логину/ключу/whatever запросившего пользователя. Т.е. внешняя обертка позволяет программно отрезать возможность получения одним клиентом данных другого и исключает случаи, когда «криворукий манагер натыкал что-то в настройках прав в длинной менюшке, в которой он ничего не понимает и вообще на листочке так написано было».

4. Простота внешнего АПИ. Вот это тоже важно. Внутри вы можете изгаляться как угодно, пилить методы на 50 входных параметров и прочие важные вещи. Внешний АПИ должен быть простым и очевидным (если вы не твердо уверены, что у клиентов нет вашего домашнего адреса). Если вы поставляете АПИ третьим лицам — не поленитесь, запилите им удобный АПИ. Чтобы в методе получения списка своих операций из параметров были какие-то осмысленные фильтры по дате, например, или типу операции. Не надо в этот запрос требовать добавить логин, пароль, текущую фазу луны и номер кредитной карты — все эти данные уже получены вами при авторизации.
Т.е. я правильно понимаю, что в публичный апи, нельзя добавлять новые данные, даже если они никак не задевают уже существующие? А чем это обусловлено?
Ну, не совсем правильно вы поняли. 2 вещи:

1. В публичный АПИ нельзя добавлять новые данные, даже если они никак не задевают уже существующие, не сменив при этом номер версии.

2. Как раз для таких вещей есть вещи вроде семантического версионирования. Версия номер x.y.z (мажорныйРелиз.минорныйРелиз.патч). Добавить новые данные, не сломав старые — это минорный релиз. В случае с АПИ, вероятно, патч можно убрать. Т.е. версия будет из 2 цифр: x.y

Допустим, у вас молодая, бурно развивающаяся апишка, версия которой на данный момент — пусть будет 3.15. Вы добавляете новые данные, не ломая старые — выпускаете версию 3.16. Всем хорошо.

До тех пор, пока потребитель, написавший свой клиент еще на версии 3.02, может работать с АПИ, не внося изменений в свой код — плюсуете вторую цифру. Как только с обновлением что-то сломалось — плюсуйте первую, и будьте добры поддерживать предыдущую версию до тех пор, пока клиенты (в разумные сроки) не смигрируют.

А обусловлено это тем, что АПИ — публичное. Им пользуется N потребителей. Нет, N мало, лучше K. И у каждого из них свой продукт, который пилится, и в который уже вложено некоторое количество человеко-часов, и от которого у владельца продукта есть определенные ожидания.

Перепилить продукт-потребитель стоит, допустим, X человеко-часов. Очевидно, миграция всех клиентов обойдется в X * K человеко-часов. Нехорошо вот так труд людей тратить.

Даже если вы ничего не сломали, в дальнейшем клиент, допустим, скажет: а вот у вас в документации написано «можно получить цвет глаз котенка вот этим методом АПИ, передав ему в качестве параметра АйДи необходимого котенка», а у меня не работает. А вы ему четко, взвешено и аргументировано: метод получения цвета глаз реализован в АПИ версии 3.17 и поддерживается с этого момента, а у вас клиентская библиотека версии 3.14. Т.е., заметьте, не «ну попробуйте обновиться, яхз», а «у вас версия библиотеки 3.14, которая не поддерживает фичу, появившуюся в версии 3.17, обновитесь до версии не ниже 3.17».

Или, допустим, я накопал библиотечку, которая над вашим АПИ обертка. И мне очень прямо важно уметь получать цвет глаз котят. Я смотрю в вашу доку, а там есть такой метод, интегрирую библиотечку — а там хрен вместо глаза.

А будь у вас номер версии, и будь в документации описано «поддерживается с версии 3.17, а параметр rgba|rgb|cmyk позволяет выбрать формат представления цвета с версии 3.19» я бы просто посмотрел, что библиотечка версии 3.14 и прошел бы мимо.

Короче, ВЕРСИОНИРУЙТЕ. Любой чих версионируйте — это экономит очень много сил как для вас, так и для вашего клиента.
1. Изменения могут коснуться внешней апи тоже. Скорее стоит рассмотреть правила версионности api, создавая тем самым условия гарантии неизменности формата данных и работы конкретной версии
2. -> 1
3. Тут решается правами. Это должно быть общим стандартом как для внутреннему пользователю, так и внешнему
4. Соглашусь, добавлю лишь то, что если это может настроить не программист, то круто

Потому, что один для клиентов, а другой для внутреннего пользования, ваш Кэп.
И клиентам совершенно не нужно знать то, что знает свой условный фронт.

Кстати, авторизационные велосипеды лучше не делать еще и из-за потенциальных дыр в безопасности — потому же, почему не стоит делать кастомные алгоритмы шифрования/хеширования вместо стандартных.

Проблемы №1-3 лекго решаются исползуя peekdata.io или cube.dev компоненты. Кстати,- такой же подход используетсья Гууглом и Яндехом.
Подпись составляется по следующему алгоритму:

массив из передаваемых параметров (GET, POST, PUT, DELETE) сортируется по названию ключа по алфавиту;
из полученного массива формируется строка запроса (например, функция http_build_query в PHP), пример «from=DATEFROM&to=DATETO…»;
и далее — соединяется по формуле: строка = имя_метода строка_запроса md5( строка_запроса ), где «имя_метода» — строка запроса, начиная от домена (с указанием версии АПИ), до начала перечисления параметров, например — '/v1/sip/'
полученная строка хешируется по алгоритму sha1 с секретным ключом пользователя: хеш = hash( строка, секретный_ключ )
и далее хеш кодируется в base64 подпись = base64_encode( хеш )


Вот кто это придумал? Особенно поражает последний пункт, который из 40-символьной регистронезависимой строки вдруг делает 56-символьную регистрозависимую. API внешнее и для широкого пользования
Есть еще поэротичнее варианты:
   $message = $x_invoice .'V' 
      . $x_amount .'I' 
      . $x_iduser .'2' 
      . $x_bank .'1' 
      . $x_cpf .'H' 
      . $x_bdate .'G' 
      . $x_email .'Y' 
      . $x_state . 'P';

   $control = strtoupper(hash_hmac('sha256', pack('A*', $message), pack('A*', $secretKey)));

Причем в ряде методов добавление символов к полю отсутствует вообще. В каких-то есть только префикс. Короче мрак, если честно. Основное назначение API — ИМХО легкая интеграция с продуктом. А на деле все превращается в камасутру и пляски с бубном.
Кстати, зачем тут нужен pack? Чтобы не латинские символы поддерживать?
Sign up to leave a comment.

Articles