Мы в Perfect Solutions на прошлой неделе написали сотое по счету API. За все это время, ценой граблей, костылей, велосипедов и рефакторинга, мы поняли, что выработали отличную стратегию «как писать API и прекратить боль и страдание».
Этот пост о версировании, поддержке, багфиксинге и полном цикле жизни API.
Под катом нет фото с большим трафиком, нет серебрянных пуль, тут даже нет картинки для привлечения внимания — только полезная выжимка нашего опыта. Под катом методология, выработанная на реальном опыте разработки, набитых шишках и сломанных грабляхъ.
Продуктовый подход
API — не «набор функций для всех», не «набор для решения любых задач», не «сделать и забыть».
API — это продукт, при том продукт, которым будут пользоваться разработчики. Вам не удастся «продать» им плохое API, выдав за хорошее. На все вопросы ответит время.
Что такое продуктовый подход к API? Это значит что API состоит из фич и багов. Фичи должны быть просты и атомарны: один метод API — воспринимается как одна фича. Фича ли, регистрация пользователя через API? Да, фича! Фича ли, отправка push-уведомления? Фича!
А это значит, что все методы API обязаны быть продуманы, описаны, разработаны и протестированы — пройти полный цикл разработки. Самые большие беды в плане отношения разработчиков к API — его непродуманность.
Атомарность операций
Если Ваше API делает в одном методе 3 INSERT в СУБД — там обязана быть транзакция. Если ее нет — это не просто будет причиной проблем, но и причиной ненайденных и невоспроизводимых из интерфейса проблем.
И еще важный момент в понятии атормарности. Фича — атомарна. Если при регистрации нового юзера из API ему обязаны быть указаны роли (из системы прав) — значит метод API для регистрации пользователя обязан в одном запросе делать обе вещи:
- Создавать пользователя
- Делать assign переданного списка ролей
Например вот такой метод, в случае yii2:
public function actionRegister($username, $password, array $roleNames)
{
...
}
Проверка всех входящих параметров и соответствие протоколам
Как и любые данные полученные от пользователя, всё что приходит в API обязано проходить валидацию. API пользуются разработчики, но они такие же пользователи, люди.
Стандартные http-ответы соответствующие реальности — это важный момент для упрощения поддержки и дебага. Некорректный запрос, непроходящая валидация — «400 Bad Request», Внутренняя ошибка — «500 Internal Server Error». Это очень важно для логирования (в логах nginx) и починки всех будущих багов. Если API всегда отдает статус 200 — будет очень сложно найти в логах причины ошибок.
Вы будете чинить баги
Вы не выкинете API, не «сделаете потом новую версию». Вы будете чинить баги в этой версии API, в этом коде и прямо завтра.
Я это говорю к тому, что как любой продукт, API — то что придется отлаживать, тестировать и поддерживать. А значит есть самый обычный набор правил:
- Соблюдайте протокол (как минимум Status Code)
- Логируйте все — на стороне API логируйте запросы и ответы, на стороне клиента — то же самое. Забавный момент — оно еще и отличатся может ;-)
- Тестируйте его, делайте ревью кода и помните что API — это продукт, пользователи которого — разработчики
- Делайте специальный параметр для дебага — чтобы на стороне клиента можно было получить не только ответ от API, но и всю отладочную информацию. Рядышком с ответом.
Никогда не верьте в то что Вы изобрели способ версирования API
Версирование API помогает терять обратную совместимость в новых методах, не выкидывая старые методы, оставляя их в старой версии. Интернет предлагает массу способов версировать API. Способов для разных фреймворков, подходов и всего прочего, но серебряной пули нет. За то есть магазин в который легко влезает почти любая пуля — location в nginx.
location /api/v1/ {
...
}
location /api/v2/ {
...
}
Такой подход позволит не только в нужный момент выкинуть старое API, но и позволит вынести новое API на другой сервер, в отдельное приложение, да вообще куда угодно. Это не «решение всех проблем», это коробочка в которую можно сложить множество ваших решений, которые будут видоизменятся со временем.
Document Drive Development
Документирование API часто является болью. Документация почти всегда не актуальна, а инструменты вроде swagger все равно требуют поддержки. Этот вопрос легко решается, если облюдать продуктовый подход — начните с документации. Вот прямо когда будете заводить задачу в вашей jira/redmine — там и опишите все что хотите от API. Прямо в формате документации.
Выложите новый метод на боевой сервер — просто скопируете документацию из задачи в ваше хранилище документации. И вуаля — ваша документация всегда актуальна.
ФП, как аналогия
Пишите простые методы API. Представьте что пишите функцию на Erlang. Приличную часть проблем несут «методы всия руси», «метод для всего» или любой метод перегруженный логикой.
Методы API должны быть атомарны, но при этом достаточны. И слишком мелкое разбиене и обратная сторона — приведут к проблемам.
Удачи!
Я коротко изложил наш субъективный опыт разработки API, но не привел никакого осмысленного кода — у вас все равно будет ваш код.
А вот все это коротко в виде тезисов:
- Продуктовый подход
- Атомарность операций
- Проверка всех входящих параметров и соответствие протоколам
- Логируйте все
- Никогда не верьте в то что Вы изобрели способ версирования API
- Document Drive Development
- ФП, как аналогия
Автор: piromanlynx