N+1 w żądaniach API

0

Hej

Załóżmy, że mamy api z edpointami:

/users/{username}/orders - zwracający listę zamówień dla danego użytkownika,
/orders/{orderID}/pruducts - zwracający produkty dla danego zamówienie

I teraz chcemy dostać wszystkie produkty które kupił dany użytkownik, najprościej byłoby po prostu strzelić pod enpoint /users a potem dla kazdego zamówienia strzelić pod /orders, ale tu powstaje problem N+1, gdy sekwencyjnie wykonujemy zapytania o produkty dla każdego zamówienia po kolei, a przeciaż te zamówienia nie są ze sobą związane, można te zapytania zrównoleglić, tylko jak? Użyć executor service z liczba watkow równą liczbie zamówień, coś podziałać z CompletableFuture?

2

Dlaczego chcesz robić to 2 strzałami?
Uderzasz pod jeden endpoint, nowy, trzeci który zwraca to co potrzebujesz. Robisz całą logikę na backendzie gdzie piszesz skomplikowane zapytanie SQL zwracające wszystkie produkty kupione przez danego użytkownika.

To ma sens gdy to jest Twoje API.

Jeśli to obce API to zignoruj moje słowa ;)

6

Tak rób, zrównoleglaj zapytanie to dostaniesz bana na API lub włączy się rate-limiter i zacznie rzucać timeout'ami.

W tym api potrzebny jest nowy endpoint do masowego pobierania zamówień.
GET /orders?byUser=$userId&fields=product
oraz
GET /products?byIds=$listOfIds (ewentualnie przerobić to na POST gdy lista będzie długa i przekroczy max długość URL).

Ale widać też że ty tam robisz jakąś analitykę czy czesanie danych. Do tego trzeba by podejść inaczej, ale trzeba mieć więcej danych (po co Ci do, dlaczego, co ma być i jak szybko...).

0
99xmarcin napisał(a):

Tak rób, zrównoleglaj zapytanie to dostaniesz bana na API lub włączy się rate-limiter i zacznie rzucać timeout'ami.

W tym api potrzebny jest nowy endpoint do masowego pobierania zamówień.
GET /orders?byUser=$userId&fields=product
oraz
GET /products?byIds=$listOfIds (ewentualnie przerobić to na POST gdy lista będzie długa i przekroczy max długość URL).

Ale widać też że ty tam robisz jakąś analitykę czy czesanie danych. Do tego trzeba by podejść inaczej, ale trzeba mieć więcej danych (po co Ci do, dlaczego, co ma być i jak szybko...).

To czysto teoretyczny przykład, z tego co rozumiem programowanie reaktywne rozwiązuje ten problem, zastanawiałem się jak podobne przypadki rozwiązuje się w blokującym świecie szczególnie teraz gdy mamy wątki wirtualne, załozenie jest takie że to obce api

1
Schaft napisał(a):

...

załozenie jest takie że to obce api

A dane są "obce" czy w ramach tej samej organizacji? Jak obce dane i interfejs, to zagadnienie redukuje się do scrappingu danych. Jeśli wszystko dzieje się w ramach tej samej organizacji, to możliwe, że dane analityczne są w zupełnie innym komponencie z innym interfejsem, ewentualnie można wnioskować o rozbudowanie interfejsu, czy procesu , tak by ordery trafiały do jakiejś bazy analitycznej.

Jaki problem rozwiązujesz pobierając historię wszystkich produktów zakupionych przez użytkownika? Może zaraz się okaże, że chcesz drugą iterację, po użytkownikach?

4

Ani Rx ani wątki nic ci tutaj nie pomogą bo to inny serwer ciebie zbanuje za walenie po api x100 i robienie im DoS.

2

z tego co rozumiem programowanie reaktywne rozwiązuje ten problem,

Co masz na myśli mówiąc "ten" problem i "rozwiązuje"? Programowanie reaktywne może i pozwoli ci wykonać kilka requestów równolegle, ale do tego nie potrzebujesz rxjava, możesz (najbanalniej) użyć .parallelStream() z ew. własną pulą forkjoinpool albo ręcznie wydłubać na ExecutorService tradycyjnie zrobić submit iluśtam zadań i poczekać na wszystkie.

Ale tak jak pisze @99xmarcin - to nie jest problem, problemem mogą być ograniczenia API na ilość zapytań, więc ja bym ten problem olał, ale 1) dowiedział się od właściciela API czy możesz robić 100 requestów równolegle, 2) dodał sobie jakiś monitoring na to, żeby dowiedzieć się, że jednak nie możesz.

0

Jaki use case to ma być? Co z tymi danymi chcesz zrobić?

Jeśli to analityka i API jest firmy trzeciej, która nie dostarcza endpointu do robienia zapytań np w standardzie OData, np. Users(1234)?$expand=Orders to robisz joba który eksportuje te dane z każdego endpointa do twojej lokalnej bazy danych i tam sobie robisz zapytania jak chcesz.

Robienie takich cudów jak opisałeś na API to proszenie się o kłopoty z dostawcą.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.