Optional jako parametr metody (Spring Boot, Spring Data)

0

Robię proste API-walidator, do którego wysyłany jest request podczas wypełniania formularzy na front-endzie.
Np. rejestruje się nowy użytkownik, wpisuje login który jest już zajęty, i dostaje od razu podpowiedź że powinien wybrać inny login bo ten jest już zajęty.
API jest wywoływane AJAXem, zwraca 200 jeśli wartość nie istnieje w bazie, albo 403 jeśli wartość istnieje. Na tej podstawie wyświetlam odpowiednie komunikaty przy formularzu.

Wymyśliłem coś, ale IDE narzeka że Optional nie powinien być przekazywany jako parametr metody. Jakie są tu inne możliwości?

Repozytorium (User rozszerza AbstractEntity)

public interface UserRepository extends CrudRepository<User, Long> {

    Optional<User> findOneByEmail(String email);

}

Kontroler - walidator

@Controller
@RequestMapping("/signupCheck")
public class SignupCheckController extends RemoteValidator<User> {

    @Autowired
    private UserRepository userRepository;

    @RequestMapping(value = "/email", method = RequestMethod.GET)
    public ResponseEntity<String> checkEmail(@RequestParam(name = "email") String email) {
        return performCheck(userRepository.findOneByEmail(email));
    }

I abstrakcja którą chcę jakoś poprawić:

public abstract class RemoteValidator<T extends AbstractEntity> {

    protected ResponseEntity<String> performCheck(Optional<T> entity) {
        if (entity.isPresent()) {
            return new ResponseEntity<>(HttpStatus.FORBIDDEN);
        } else {
            return new ResponseEntity<>(HttpStatus.OK);
        }
    }

Ponieważ jednak czytałem, że nie powinno się używać Optionali jako parametrów metod, zastanawiam się jak można to inaczej rozwiązać?

  1. Zwrócić z repozytorium po prostu Usera, przekazać i zrobić null-checka
  2. Zastosować jakiś wzorzec projektowy typu Null Object
  3. Albo zupełnie zmienić koncepcję walidatora i wykorzystać mechanizmy Springa, stworzyć klasę wyjątku na niepoprawne dane i zwracać 4xx jeśli wyjątek wystąpi?

Dzięki

1

Ludzie często przeginają z Optionalami i tak samo jest w tym przypadku. Jeśli nie wykonujesz szeregu operacji na obiekcie, to nie ma sensu opakowywać go już w DAO w Optionala, szczególnie jeśli jedyne co robisz to sprawdzasz czy w tym Optionalu faktycznie coś jest. Optionale są fajne, ale ja preferuję używanie ich w węższym kontekście niż cały flow aplikacji.

Tyle o samym optionalu. Problemu nie byłoby gdybyś zamiast wybrania z bazy i sprawdzenia czy faktycznie coś wybrałeś, napisał zapytanie, które zwróci ci booleana czy taki użytkownik w bazie jest, czy też go nie ma.

0

API jest wywoływane AJAXem, zwraca 200 jeśli wartość nie istnieje w bazie, albo 403 jeśli wartość istnieje.

Bosz, po co jakieś takie udziwienia?
Powinieneneś zwracać zawsze 200 jeśli sprawdzenie danych zostało poprawienie przeprowadzone i tyle.
403 informuje że jest jakiś błąd, a gdzie masz błąd w tym że nazwa użytkownika jest zajęta?
Powinno wrócić true lub false i tyle w temacie:

EDIT:
oczywiście tutaj mówimy o sytuacji gdzie robimy walidację zdalną, czyli klikasz ->walidacja ->przeszło->lecą dane.
A co do reszty wystarczy ustawić na bazie danych unique na username i wtedy walnie jakiś błąd ConstraintViolationException -> przechwytujes taki w Contoller Advice i zwracasz na przykład 409

0
scibi92 napisał(a):

A co do reszty wystarczy ustawić na bazie danych unique na username i wtedy walnie jakiś błąd ConstraintViolationException -> przechwytujes taki w Contoller Advice i zwracasz na przykład 409

A co jeśli chcielibyśmy sprawdzić przed zapisem do bazy, na przykład przy utracie focusa na polu z loginem? ;)

0

No to jak pisałem rest api do sprawdzania czy username jest dostępny np. robimy w dao metode która bierze user po username i sprawdza czy rezultat == null i taki boolean zwracamy

3

@Vatone, robisz błąd z serii tych o których mówiłem na Confiturze ;) Sam takie robiłem. Generalnie nie potrzebujesz metody performCheck ponieważ Optional ma metodę map:

entity.map(o -> HttpStatus.OK).orElse(HttpStatus.FORBIDDEN);

W takim wypadku cała ifologia metody została zamknięta w sposobie w jaki Optional obsługuje map.

0

@Koziołek
Ooo, tak, to jest dobre, czegoś takiego potrzebowałem! I teraz pytanie czy lepiej Optionalowy map czy lepiej boolean i ifologia. To pierwsze wydaje się elegantsze, ale z drugiej strony ja wcale nie potrzebuję wyciągać całego Usera z bazy, tylko informację czy mail/login jest już zajęty.

@scibi92
Czy udziwnienia, nie wiem... Może faktycznie to 403 to trochę niefortunny kod błędu w tym przypadku. Znalazłem bibliotekę do walidacji formularzy w Bootstrapie (http://1000hz.github.io/bootstrap-validator/), jest tam opcja walidacji zdalnej i wymagane jest żeby serwer zwracał 200/4xx jako kody. Chodzi oczywiście o walidację asynchroniczną, przy wpisywaniu, zatwierdzanie formularza w celu walidacji mnie zupełnie nie interesuje... Choć oczywiście waliduję dane też po stronie serwera przed zapisaniem do bazy danych.

0

Skoro musisz tylko mail, to można by spróbować:

@Query("Select u.email from User u where u.email= ?#{[0]}")
Optional<String> getEmail(String email);

i dalej Optional.map.

0

Mam pytanie. Czysto hipotetyczne.
Robie metode publiczna z @transactional.
W srodku niej szukam encji i updatuje (nie mowie, ze to dobre)

Robie find. Dostaje encje. Robie set na jakims polu. Encja zupdatowana.

Rozumiem, ze w przypadku tez wszystko zachowa sie tak samo?

1 użytkowników online, w tym zalogowanych: 0, gości: 1