Нашият опит с разработката на API Gateway

Някои компании, включително нашият клиент, развиват продукта си чрез партньорска мрежа. Например, големи онлайн магазини са интегрирани с куриерски услуги - поръчвате продукт и скоро получавате номер за проследяване на пратката. Друг пример - заедно с авиобилета си, купувате застраховка или билет за аеропортски експрес.

За това се използва един API, който трябва да бъде предоставен на партньорите чрез API Gateway. Тази задача решихме ние. В тази статия ще разкажем подробности.

Дадено: екосистема и API портал с интерфейс, където потребителите са регистрирани, получават информация и т.н. Нужно е да създадем удобен и надежден API Gateway. В процеса трябваше да осигурим

  • регистрация,
  • контрол на свързването с API,
  • мониторинг на начина, по който потребителите използват окончателната система,
  • отчитане на бизнес показателите.

Нашият опит с разработката на API Gateway

В статията ще споделим опита си от създаването на API Gateway, в хода на който решавахме следните задачи:

  • автентикация на потребителя,
  • авторизация на потребителя,
  • модификация на входящата заявка,
  • проксиронане на заявката,
  • постобработка на отговора.


Има два вида управление на API:

1. Стандартно, което работи по следния начин. Преди да се свърже, потребителят тества възможностите, след това заплаща и интегрира на своя сайт. Най-често се използва в малкия и среден бизнес.

2. Голямо B2B управление на API, при което компанията първо взема бизнес решение за свързване, става партньор на компанията с договорни задължения, а след това се свързва с API. И едва след разрешаването на всички формалности, компанията получава тестов достъп, преминава тестване и навлиза в продукция. Но това е невъзможно без управленско решение за свързване.

Нашият опит с разработката на API Gateway

Нашето решение

В тази част ще разкажем за създаването на API Gateway.

Крайни потребители на създадения API шлюз са партньорите на нашия клиент. За всеки от тях вече разполагаме с необходимите договори. Трябва само да разширим функционалността, отбелязвайки предоставения достъп до шлюза. Съответно, нужен е контролируем процес на свързване и управление.

Разбира се, можеше да се използва готово решение за управление на API и създаване на API Gateway в частност. Например, такова можеше да бъде Azure API Management. То, което не ни подходи, беше, че в нашия случай вече имахме API портал и огромна екосистема, изградена около него. Всички потребители вече бяха регистрирани, те вече разбираха къде и как могат да получат необходимата информация. В API портала вече съществуваха нужните интерфейси, просто ни беше необходим API Gateway. Всъщност, това и започнахме да разработваме.

Това, което наричаме API Gateway — е своего рода прокси. Тук отново имахме избор — можем да напишем свой прокси, или да изберем нещо готово. В този случай избрахме втория път и решихме да използваме свързване nginx+Lua. Защо? Необходим ни беше надежден, тестван софтуер, който поддържа мащабируемост. Не искахме след реализацията да проверяваме и коректността на бизнес логиката, и коректността на работата на проксито.

Всеки уеб сървър има конвейер за обработка на заявки. В случай на nginx, той изглежда по следния начин:

Нашият опит с разработката на API Gateway

(схема от GitHub Lua Nginx)

Нашата цел беше да се вмъкнем в този конвейер в момента, в който можем да модифицираме входящата заявка.

Искаме да създадем прозрачен прокси, така че функционално заявката да остане такава, каквато е дошла. Ние просто контролираме достъпа до крайния API, помагайки на заявката да стигне до него. В случай, че заявката беше некоректна, грешката трябва да се покаже от крайния API, а не от нас. Единствената причина, поради която можем да откажем заявка — е заради липсата на достъп от страната на клиента.

За nginx вече съществува разширение на Lua. Lua — е скриптов език, той е много лек и лесен за усвояване. Така че необходимата логика реализирахме с помощта на Lua.

Конфигурацията на nginx (аналогия на маршрута на приложението), където се извършва цялата работа, е напълно ясна. Интересна е последната директива — post_action.

location /middleware {
      more_clear_input_headers Accept-Encoding;
      lua_need_request_body on;
      rewrite_by_lua_file 'middleware/rewrite.lua';
      access_by_lua_file 'middleware/access.lua';
      proxy_pass https://someurl.com;
      body_filter_by_lua_file 'middleware/body_filter.lua';
      post_action /process_session;
}

Нека разгледаме какво се случва в тази конфигурация:
more_clear_input_headers — изчиства стойността на специфицираните след директивата хедери.
lua_need_request_body — регулира дали да се прочете оригиналното тяло на заявката, преди да се изпълнят директивите rewrite/access/access_by_lua или не. По подразбиране nginx не чете тялото на заявката на клиента, и ако е необходимо да получите достъп до него, тази директива трябва да има стойност on.
rewrite_by_lua_file — път до скрипта, в който е описана логиката за модификация на заявката
access_by_lua_file — път до скрипта, в който е описана логиката, проверяваща наличието на достъп до ресурса.
proxy_pass — url, на който ще се проксира заявката.
body_filter_by_lua_file — път до скрипта, в който е описана логиката за филтриране на заявката преди да бъде върната на клиента.
И накрая, post_action — официално недокументирана команда, с която могат да се изпълняват допълнителни действия след като отговорът е даден на клиента.

Нека разгледаме последователно как решихме своите задачи.

Авторизация и аутентификация, и модификация на заявката

Авторизация

Авторизацията и аутентификацията изградихме с помощта на достъп чрез сертификат. Има коренов сертификат. На всеки нов клиент на поръчителя се генерира личен сертификат, с който може да получи достъп до API-то. Този сертификат се конфигурира в секцията server на настройките на nginx.

ssl on;
ssl_certificate /usr/local/openresty/nginx/ssl/cert.pem;
ssl_certificate_key /usr/local/openresty/nginx/ssl/cert.pem;
ssl_client_certificate /usr/local/openresty/nginx/ssl/ca.crt;
ssl_verify_client on;

Модификация

Може да възникне основателен въпрос: какво да правим с сертификатиран клиент, ако внезапно решим да го изключим от системата? Не можем да преиздаваме сертификати за всички останали клиенти.

Така плавно преминахме към следващата задача — модификация на оригиналната заявка. Оригиналната заявка на клиента, по принцип, не е валидна за крайния систем. Една от задачите е да допълним заявката с липсващите части, за да я направим валидна. Тайната е, че липсващите данни са различни за всеки клиент. Знаем, че клиентът идва при нас със сертификат, от който можем да вземем отпечатък и да извлечем необходимите данни за клиента от базата.

Ако в някакъв момент се наложи да изключим клиента от нашата услуга, данните му ще изчезнат от базата и той няма да може да прави нищо.

Работа с данните на клиента

Трябваше да осигурим висока наличност на решението, особено що се отнася до начина, по който получаваме данните на клиента. Сложността идва от факта, че основният източник на тези данни е външна услуга, която не гарантира непрекъснато и достатъчно високо качество на работа.

Затова трябваше да осигурим висока наличност на данните на клиентите. Като инструмент избрахме Hazelcast, който ни предоставя:

  • бърз достъп до данни,
  • възможност за организиране на клъстър от няколко възела с репликирани данни на различни възли.

Следвахме най-простата стратегия за доставяне на данни в кеша:

Нашият опит с разработката на API Gateway

Работата с крайната система става в рамките на сесии и има лимит на максималното количество. Ако клиентът не е затворил сесията, ще трябва да го направим ние.

Данните за отворената сесия идват от крайната система и първоначално се обработват на страната на Lua. Решихме да използваме Hazelcast за запазване на тези данни с джоб, написан на .NET. След това на определени интервали проверяваме правото на живот на отворените сесии и затваряме просрочените.

Достъп до Hazelcast и от Lua, и от .NET

Клиенти на Lua за работа с Hazelcast няма, но Hazelcast има REST API, който решихме да използваме. За .NET обаче има клиент, чрез който планирахме да получим достъп до данните на Hazelcast от страната на .NET. Но не тук е проблемът.

Нашият опит с разработката на API Gateway

При запазването на данни чрез REST и извлечението чрез .NET клиента се използват различни сериализатори/десериализатори. Следователно е невъзможно да се сложат данни чрез REST и да се извлекат с .NET клиента и обратното.

Ако има заинтересовани, ще разкажем по-подробно за този проблем в отделна статия. Спойлер — на схемата.

Нашият опит с разработката на API Gateway

Логиране и мониторинг

Нашият корпоративен стандарт за логиране през .NET е Serilog, всички логове в крайна сметка попадан в Elasticsearch, а анализа им проведем чрез Kibana. Нещо подобно искахме да направим и в този случай. Единственият клиент клиент за работа с Elastic на Lua, който беше намерен, се провали при първия require. И ние използвахме Fluentd.

Fluentd — open source решение за осигуряване на единен слой за логиране на приложението. Позволява събиране на логове от различни слоеве на приложението и последвацно извеждане в единен източник.

API Gateway работи в K8S, затова решихме да добавим контейнер с fluentd в същото поду, за да пишем логове в наличния отворен TCP порт на fluentd.

Също така проучихме как ще се държи fluentd, ако няма свързаност с Elasticsearch. В продължение на два дни в шлюза непрекъснато постъпваха заявки, към fluentd се изпращаха логове, но на fluentd IP адресът на Elastic беше блокиран. След възстановяване на свързаността fluentd отлично пренесе абсолютно всички логове в Elastic.

Заключение

Избраният подход за реализация ни позволи да доставим реално работещ продукт в производствена среда само за 2.5 месеца.

Ако някога ви се наложи да се занимавате с подобни неща, съветваме ви първо да разберете ясно каква задача решавате и какви ресурси вече имате. Бъдете внимателни към сложността на интеграцията с вече съществуващите системи за управление на API.

Разберете за себе си какво точно ще разработвате — само бизнес логиката за обработка на запитвания или, както беше в нашия случай, прокси изцяло. Не забравяйте, че всичко, което направите сами, трябва да бъде впоследствие внимателно тествано.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster