Pierwsze API MojeSklepu powstało 10 lat temu. Przez cały ten czas pracujemy nad istniejącymi wersjami API oraz opracowujemy nowe. A kilka wersji API już zdążyło trafić do zapomnienia.
W tym artykule będzie wiele informacji: jak powstawało API, po co jest potrzebne usłudze w chmurze, co daje użytkownikom, na jakie pułapki natrafiliśmy oraz co chcemy robić dalej.
Nazywam się Oleg Alekseev , jestem dyrektorem technicznym i współzałożycielem MojeSklepu.
Po co tworzyć API dla usługi
Nasi klienci, a jest ich dziesiątki tysięcy, aktywnie korzystają z rozwiązań w chmurze: bankowości, sklepów internetowych, prowadzenia gospodarki magazynowej, CRM. Po podłączeniu do jednego — trudno się zatrzymać. I oto piąta, ósma, dziesiąta usługa sprawia, że praca przedsiębiorcy staje się łatwiejsza, ale dane między tymi usługami są przenoszone ręcznie. Praca zamienia się w koszmar.
Oczywistym rozwiązaniem jest umożliwienie użytkownikom przekazywania danych między usługami w chmurze. Na przykład importowanie i eksportowanie danych w postaci plików, które następnie można załadować do odpowiedniej usługi. Pliki zazwyczaj dostosowuje się do formatu każdej usługi. To bardziej lub mniej prosta ręczna praca, ale w miarę wzrostu liczby tych usług staje się to coraz trudniejsze.
Dlatego następnym krokiem jest API. Dzięki temu usługa w chmurze zyskuje na tym, że łączy kilka usług w jednym punkcie. Pojawienie się takiego ekosystemu przyciąga nowych klientów dzięki dodatkowym możliwościom. Produkt z nową funkcjonalnością staje się bardziej opłacalny i użyteczny.
Jeśli tworzysz własne interfejsy programistyczne, przyciągasz zewnętrznych sprzedawców w postaci programistów, którzy poznają Twój produkt dzięki API. Zaczynają budować rozwiązania na podstawie oferowanego API i zarabiają pieniądze na automatyzacji zadań swoich klientów.
System księgowy MojeSklepu oparty jest na prostych procesach. Główne zadanie to praca z dokumentami źródłowymi, możliwość przyjmowania i wydawania towaru, uzyskiwanie raportów dla biznesu na podstawie dokumentów źródłowych. Ponadto występuje przekazywanie danych, na przykład do chmurowej księgowości, oraz ich pozyskiwanie z systemów bankowych lub punktów sprzedaży. Ponadto współpracujemy z sklepami internetowymi: uzyskujemy informacje o produktach i przesyłamy dane o stanach magazynowych.

Pierwsze API MojeMagazyny
Przez 10 lat pracy MojeMagazyny z API zgromadziliśmy różnorodne integracje, które umożliwiają wymianę danych, współpracę z bankami, realizację płatności oraz wykorzystanie telefonii zewnętrznej.
W pierwszym roku umożliwiliśmy eksport dowolnych danych w formacie XML. Wówczas użytkownikom łatwiej było i wygodniej trzymać dane offline, a nie w jakiejś tam chmurze, więc im to zapewniliśmy. Eksport uruchamiano ręcznym eksportem z interfejsu. Wówczas API nie można było jeszcze tak nazwać.
Wtedy zaczęliśmy współpracę z firmą Rusagro — oni już korzystali z 'dorosłego' ERP do planowania produkcji i sprzedaży, a my zautomatyzowaliśmy załadunek wagonów w MoimMagazynie. Tak pojawiły się pierwsze zalążki prawdziwego API: wymiana między naszym serwisem a ERP odbywała się poprzez przesyłanie dużego pliku z danymi we wszystkich typach dokumentów.
To niezła opcja dla wsadowej wymiany danych, ale razem z dokumentami trzeba było przekazywać ich zależności: informacje o towarach, kontrahentach i magazynach. Taką chaotyczną strukturę łatwo jest wygenerować podczas eksportu, ale dość trudno zanalizować podczas importu, ponieważ w jednym pakiecie przychodzą wszystkie informacje: zarówno o nowych dokumentach, jak i już istniejących.
Pierwsze XML API nie przetrwało długo — dwa lata później zaczęliśmy jego przebudowę. Już na początku jego działania popełniliśmy kilka błędów przy budowie interfejsu programowania.

Jak powstawało XML API: ilustracja stworzona przez jednego z naszych architektów. Przy okazji, czekajcie na jego artykuły.
Oto nasze główne błędy:
- Rozmieszczenie JAXB było zrobione bezpośrednio na entity beans. Do komunikacji z bazą danych używamy Hibernate, a na tych samych beanach zrobiono rozmieszczenie JAXB. Ten błąd ujawniał się niemal natychmiast: każda aktualizacja struktury danych wymagała natychmiastowego powiadomienia wszystkich, którzy korzystali z API, lub stworzenia rozwiązań, które zapewniałyby zgodność z poprzednią strukturą danych.
- API rozwijał się jako pewnego rodzaju dodatek, i początkowo nie zdefiniowaliśmy, jaką część produktu on stanowi. Nie zastanawialiśmy się również, czy API jest czymś ważnym, czy konieczne jest utrzymywanie zgodności wstecznej dla jego pierwszych klientów. Na pewnym etapie liczba użytkowników API stanowiła około 5% ogólnej liczby, i nie zwracaliśmy na nich uwagi. Wprowadzona wtedy uniwersalna filtracja spowodowała, że zaczęto nas wykorzystywać jako backend. Ta filtracja była zupełnie inna niż GraphQL, ale coś w tym stylu — działała za pośrednictwem wielu parametrów w zapytaniach. Z takim potężnym narzędziem użytkownikom było trudno się oprzeć i zaczęli wysyłać zapytania bezpośrednio z UI swoich sklepów internetowych. Sytuacja stała się nieprzyjemnym zaskoczeniem, ponieważ świadczenie takiej usługi powinno wymagać innego modelu cenowego i zupełnie innego postrzegania samego API jako produktu.
- Ponieważ API rozwijało się nie jako podstawowy produkt, dokumentacja API była tworzona i publikowana w trybie doraźnym — poprzez inżynierię wsteczną. Ten sposób wydaje się dość prosty i wygodny, ale stoi w sprzeczności z pracą na podstawie kontraktu. To sytuacja, gdy istnieje pewny komponent z preinstalowanym schematem działania. Programista wdraża go zgodnie z tym schematem i zadaniem, komponent przechodzi testy, a klient otrzymuje produkt, który odpowiada zamysłowi analityka. Inżynieria wsteczna natomiast wprowadza na rynek produkt, który po prostu istnieje: z obejściami, dziwnymi rozwiązaniami i wynalazkami zamiast potrzebnej funkcjonalności.
- Cały strumień zapytań, który przychodził przez API, można było analizować jedynie jako log Nginx’a lub serwera aplikacji. To nie pozwalało na wyodrębnienie obszarów tematycznych, chyba że rozdzielić je według użytkowników i subskrybentów. Jeśli nie ma możliwości regulowania rejestracji aplikacji lub klientów, analiza sytuacji staje się niemożliwa. Ten problem w najmniejszym stopniu wpłynął na rozwój API, bardziej dotyczy zrozumienia jego popularności i funkcjonalności.
Próba numer dwa: REST API
W 2010 roku próbowaliśmy zbudować system wymiany z internetową księgowością — BuchSoft. Nie udało się. Jednak w trakcie integracji powstało pełnoprawne API: usługę REST do wymiany, w której nie było dowolności, jak w przypadku wywołań RPC. Cała komunikacja z API została sprowadzona do standardowego trybu REST: w ciągu żądania znajduje się nazwa encji, a operacja, która jest z nią przeprowadzana, jest określana za pomocą metody http. Dodaliśmy filtrację według momentu aktualizacji encji, dzięki czemu użytkownicy mieli możliwość budowania replikacji ze swoimi systemami.
W tym samym roku pojawiło się API do eksportu stanów magazynowych i towarowych. Użytkownicy zyskali dostęp через API do najbardziej wartościowych części systemu — wymiany dokumentów pierwotnych oraz danych kalkulacyjnych dotyczących stanów i kosztów towarów.
W grudniu 2015 roku RetailCRM opublikował pierwszą zewnętrzną bibliotekę dostępu do naszego API. Zaczęto ją dość intensywnie wykorzystywać, a popularność usługi ogólnie rosła, obciążenie API rosło szybciej niż obciążenie interfejsu webowego. Pewnego dnia wzrost przekształcił się w skok obciążenia.


I ten skok, który pokazuje strzałka po lewej stronie, wprawił w totalne zdziwienie serwer obsługujący nasze API. Przez tydzień analizowaliśmy, co dokładnie generuje to obciążenie. Okazało się, że to te same zapytania, które były przesyłane do naszego API z frontów klientów. Całość wygenerowało około 50 klientów. Wtedy zrozumieliśmy jeden z naszych błędów — całkowity brak limitów.
W rezultacie wprowadziliśmy limit na liczbę jednoczesnych zapytań. Z jednego konta można było jednocześnie otworzyć nie więcej niż dwa zapytania. To wystarczająco dużo, aby działać w trybie replikacji do wymiany danych w trybie paczkowym. A ci, którzy chcieli wykorzystać nas jako backend, od tego momentu musieli bardziej dostosować się do taryf, ponieważ wprowadzili w swoich programach obsługę wielu kont.
Wprowadzamy porządek
Już od 2014 roku zapotrzebowanie na istniejące API stało się ważną częścią biznesu, a samo API generowało największą ilość danych w wymianie informacji z klientami. W 2015 roku uruchomiliśmy projekt porządkowania API. Wybraliśmy jako format JSON zamiast XML i zaczęliśmy budować go na podstawie szczególnych cech, które ujawniliśmy podczas wdrażania poprzedniej wersji:
- Możliwość zarządzania wersjami. Wersjonowanie umożliwia rozwijanie nowej wersji bez wpływania na istniejącą aplikację i nie zakłócając pracy użytkowników.
- Możliwość, aby użytkownik widział metadane w odpowiedzi, którą otrzymuje.
- Możliwość wymiany dużych dokumentów. Jeśli przetwarzamy dokument z ilością pozycji większą niż 4-5 tysięcy, staje się to problemem dla serwera: długa transakcja, długi żądanie http. Zbudowano specjalny mechanizm, który pozwala aktualizować dokument częściami i zarządzać poszczególnymi pozycjami tego dokumentu, wysyłając je na serwer.
- Narzędzia do replikacji — były także w poprzedniej wersji.
- Limity obciążenia — jako dziedzictwo problemów, na które natrafiono w poprzedniej wersji. Wprowadzono limity na liczbę żądań w danym czasie, liczbę równoległych żądań i żądań z jednego adresu ip.
Od tego czasu wydaliśmy dwie minorowe wersje API i uruchomiliśmy kilka specjalistycznych API, ale ogólny podejście pozostało bez zmian. Zaktualizowany format wymiany i nowa architektura pozwoliły szybciej poprawiać braki w API.
API MojeMagazyny dziś
Dziś API MojeMagazyny rozwiązuje wiele zadań:
- wymiana danych z sklepami internetowymi, systemami księgowymi, bankami;
- uzyskiwanie danych obliczeniowych, raportów;
- użycie jako zaplecze dla aplikacji klienckich — nasze aplikacje mobilne i stacjonarna kasa działają przez API
- wysyłanie powiadomień o zmianach danych w MoimMagazynie — webhooks;
- telefonia;
- systemy lojalnościowe.
Na podstawie API nasz dyrektor generalny Askar Rachimberdiev w ciągu czterech godzin napisał bota Telegram, który pobiera przez API stany magazynowe:
Teraz suche cyfry.
Oto nasze statystyki dotyczące starego REST API:
- 400 firm;
- 600 użytkowników;
- 2 mln żądań dziennie;
- 200 GB/dziennie ruchu wychodzącego.
A oto, do czego doszliśmy w przypadku wszystkich API MojeMagazyny:
- ponad 70 integracji (część z nich można zobaczyć tutaj );
- 8500 firm;
- 12 000 użytkowników;
- 46 mln żądań dziennie;
- 2 TB/dziennie ruchu wychodzącego.
Co dalej
Plany rozwoju API są obecnie aktywnie dyskutowane. Staramy się uwzględnić doświadczenia użytkowników, które nam przekazują. Nie zawsze i nie wszystko udaje się zrobić od razu, ale nowa wersja API z bardziej intuicyjnymi metadanymi i uproszczoną strukturą, a także OAuth do autoryzacji, zbliża się wielkimi krokami.
Aktualności można śledzić na specjalnej stronie dla deweloperów integrujących się z MoimSklad: .
Źródło: habr.com
