Wpis z mikrobloga

Kurde, muszę się poradzić, bo chyba trochę się pogubiłem. Mam takie trzy metody jak na obrazku. Pierwsza zwraca profil użytkownika, jako argument przyjmuje użytkownika, który przychodzi z fasady. Jak widać, mapowanie i zwrot obiektu DTO. Zastanawiam się czy ten Optional ma tam sens. Wykorzystuję go w kontrolerze i dzięki temu zwracam status 200, albo 404.

Sama fasada o której wcześniej wspominałem wygląda tak, że jest w niej jedna metoda w której pobierany jest użytkownik z SecurityContextu, następnie jest wyszukiwany po emailu, no i jeśli istnieje to jest zwracany, a jeśli nie to jest rzucany wyjątek.

W drugiej metodzie podobnie, tylko jest tam jeszcze aktualizacja pól związanych z profilem użytkownika i po aktualizacji jest zwracane DTO. Wiem, że metoda PATCH nie powinna zwracać body, tylko sam status 204. Nie wiem jak powinienem to zrobić żeby było dobrze. Zastanawiam się czy nie ustawić voida jako typ zwracany z metod updateUserProfile() i updateUserPassword(). Jak w takim przypadku zwracać 404 w razie gdy użytkownik się nie znajdzie? Może trzeba przerobić fasadę żeby zwracała typ Optional, ale wiem, że nie jest to zgodne z ideą Optionala. Co byście poradzili?

#java #spring
Pobierz VirtualSlimShady - Kurde, muszę się poradzić, bo chyba trochę się pogubiłem. Mam taki...
źródło: kod
  • 12
@VirtualSlimShady: Ekspertę nie jestem, ale:
1. PATCH to zły pomysł, zamiast tego lepiej użyć PUT albo POST.
2. Wrapowanie w Optional w linii 111 jest bezcelowe.
3. " Jak w takim przypadku zwracać 404 w razie gdy użytkownik się nie znajdzie?" - jakiś customowy wyjątek typu UserNotFoundException który łapie kontroler i zwraca wtedy 404.
@VirtualSlimShady nie do końca rozumiem pytanie ale wydaje mi się że zwracanie Optionala ma sens. To znaczy w twoim przypadku nie bo wywołujesz Optional.of czyli juz zakładasz ze obiekt nie będzie nullem (jak zakładasz ze może być null to ofNulable). Jak nie chcesz uzależniać statusu http od Optionala to możesz wyrzucić wyjątek i zrobić na niego exception habdler aby mapowal się na np. 404
@Karatte: @Patres: robię API, działam na tokenie JWT, każde zapytanie przechodzi przez te filtry, więc jeśli wyjątek będzie rzucany w filtrach to @ExceptionHandler nie zadziała. Użytkownik jest pobierany przy każdym zapytaniu po nazwie wyciągniętej z JWT, filtr wywołuje UserDetailsService i tam jest rzucany wyjątek. To działa chyba tylko na wyjątki rzucane w metodach serwisowych.
@Karatte: @Patres: widzę, że sprawa jest bardziej skomplikowana, bo robi się to mało optymalne. Użytkownik pobierany jest teraz dwa razy, raz w filtrze na początku requestu i drugi raz pobierany jest w tej fasadzie. Mam dwa selecty do tabeli użytkownika. Można to jakoś lepiej rozwiązać?
@VirtualSlimShady: Różnica między PATCH, a PUT:
- PATCH nie powinien zmieniać całego obiektu. Przekazujesz tylko zmieniane pola, reszta jest nietykana (meaning, nie nullujesz tego czego nie przekazałeś).
- PUT: pola, których nie przekażesz, są czyszczone (przekazujesz 'null').

Zwróć uwagę, że obie metody powinny być idempotentne.

Idea optionala: tam, gdzie zwracasz obiekt lub null zwróć optionala.
Jeśli masz inny sposób na przekazanie, że nie znaleziono użytkownika to też fajnie. Tylko miej na
@draxgar: tak, dlatego używam PATCHA do aktualizacji. Zastanawiam się też nad rozdzieleniem użytkownika i profilu użytkownika na dwie osobne encje. Jednak najpierw chciałbym rozwiązać problem z optymalizacją. Teraz, ta fasada, w takiej formie jak na obrazku chyba nie ma sensu? Użytkownik jest pobierany przy każdym zapytaniu w filtrze po nazwie wyciągniętej z tokenu JWT. Za chwilę jest pobierany drugi raz kiedy potrzebuję wyciągnąć coś konkretnie dla tego użytkownika. Jeden request, 2
Pobierz VirtualSlimShady - @draxgar: tak, dlatego używam PATCHA do aktualizacji. Zastanawiam ...
źródło: facade
@VirtualSlimShady: hibernate cacheuje dane, albo możesz włączyć cache, aby nie wykonywał dwóch identycznych selectów na bazie.
Możesz użyć @Cacheable.
Aby spring cię zalogował, musisz uderzyć do bazy. Później masz dwie opcje: wstrzykiwać sobie użytkownika i przepychać go przez wszystkie warstwy lub ponownie odpytać bazę.
Mówiłem ci już o tym kiedyś....

w linii #23 możesz użyć return appRepository.... .orElseThrow(() -> new UsernameNotFoundException
@draxgar: no to właśnie tak robię... wstrzykuję użytkownika i przepycham go przez wszystkie warstwy, przecież po to jest ta fasada. Tylko teraz przy API i JWT są dwa identyczne zapytania do tabeli użytkownika, pierwsze w filtrze i drugie w kontrolerze robi ta fasada i dlatego chcę to zoptymalizować żeby chociaż w obrębie jednego requestu nie było dwóch identycznych zapytań do bazy danych.