W której warstwie powinna znajdować się walidacja?

18

Tworzę Rest API za pomocą Spring Boot i używam Hibernate Validation do sprawdzania poprawności danych wejściowych.

Ale potrzebuję również innych rodzajów sprawdzania poprawności, na przykład gdy trzeba zaktualizować dane, jeśli identyfikator firmy nie istnieje, chcę zgłosić niestandardowy wyjątek.

Czy ta walidacja powinna znajdować się na warstwie usługowej czy kontrolującej?

Warstwa serwisowa:

 public Company update(Company entity) {
    if (entity.getId() == null || repository.findOne(entity.getId()) == null) {
        throw new ResourceNotFoundException("can not update un existence data with id : " 
            + entity.getId());
    }
    return repository.saveAndFlush(entity);
}

Warstwa kontrolera:

public HttpEntity<CompanyResource> update(@Valid @RequestBody Company companyRequest) {
    Company company = companyService.getById(companyRequest.getId());
    Precondition.checkDataFound(company, 
        "Can't not find data with id : " + companyRequest.getId());

    // TODO : extract ignore properties to constant

    BeanUtils.copyProperties(companyRequest, company, "createdBy", "createdDate",
            "updatedBy", "updatedDate", "version", "markForDelete");
    Company updatedCompany = companyService.update(company);
    CompanyResource companyResource = companyAssembler.toResource(updatedCompany);
    return new ResponseEntity<CompanyResource>(companyResource, HttpStatus.OK);
}
fdarmanto
źródło

Odpowiedzi:

8

Zarówno warstwa kontrolera, jak i warstwa usługi udostępniają określone interfejsy. Interfejsy definiują umowy dotyczące sposobu używania interfejsu. Kontrakt zwykle oznacza, jakich argumentów (oraz ich rodzajów i wartości) należy się spodziewać, które wyjątki można zgłaszać, jakie skutki uboczne są tworzone itp.

Teraz sprawdzanie poprawności polega głównie na egzekwowaniu umowy dotyczącej metody aktualizacji kontrolera () i metody aktualizacji warstwy usług (). Obie mają bardzo podobną umowę, więc byłoby naturalne, gdyby walidacja (wykonanie umowy) również była wspólna.

Jednym z możliwych sposobów jest oddzielenie walidacji tej umowy i wywołanie jej w obu warstwach. Jest to zazwyczaj najbardziej jasne - każda klasa / metoda egzekwuje swój własny kontrakt, ale często jest niepraktyczna z powodu wydajności (dostępu do bazy danych) lub z innych powodów.

Inną możliwością jest delegowanie tego sprawdzania poprawności do warstwy usług, przy jednoczesnym wyraźnym zdefiniowaniu zachowania w przypadku niepowodzenia sprawdzania poprawności w umowie dotyczącej warstwy usług. Warstwa usługowa zazwyczaj zwróci ogólny błąd sprawdzania poprawności (lub wyjątek zgłaszania), a warstwa kontrolera będzie chciała zareagować w określony sposób na błąd - w tym przypadku zwrócimy 400 Błędne żądanie, aby zasygnalizować, że żądanie przychodzące było nieprawidłowe.

W tym projekcie istnieje niebezpieczeństwo nadmiernego sprzężenia między logiką biznesową w warstwie usług (która powinna być dość ogólna) a kontrolerem (który obsługuje logikę integracji).

W każdym razie jest to dość kontrowersyjne pytanie, a 100 osób odpowie 100 odpowiedziami. To tylko moje zdanie.

qbd
źródło
1

Dane wejściowe należy sprawdzić w warstwie serwisowej.

„Nie mogę znaleźć identyfikatora” to warunek błędu logicznego. Powinien więc zostać wyrzucony z warstwy kontrolera.

To znowu zależy od twoich warstw / projektu.
Co ma robić warstwa usługi i czego oczekuje się od warstwy kontrolera.

Bez papieru
źródło
Odpowiedź nie powinna wymagać dodatkowych wyjaśnień od pytania. Jeśli pytanie wymaga wyjaśnienia, należy je skomentować i ewentualnie zgłosić do zamknięcia, jeżeli jest zbyt niejasne. Tak, zdaję sobie sprawę, że nie masz reputacji żadnego z tych działań.
„Sprawdzanie danych wejściowych” jest niejednoznaczne. Na przykład mogę umieścić atrybut Wymagane w polu, aby wskazać, że musi być ono wypełnione, ale mogę też umieścić złożony niestandardowy atrybut, który sprawdza, na przykład, czy wartość jednego pola jest większa od drugiego. IMHO, walidacja Porównaj „pachnie” znacznie bardziej warstwą usług biznesowych niż warstwą kontrolera.
JustAMartin
1

Sprawdzanie poprawności hibernacji to sprawdzanie integralności danych. Aby uniknąć wyjątków RuntimeExceptions z bbdd. Są to właściwie te same walidacje, które powinieneś kontrolować za pomocą Constrains . Ponieważ tylko warstwa biznesowa powinna zasilać warstwę trwałości, możesz (lub nie, zależnie od ciebie) ufać poprawności danych pochodzących z warstwy biznesowej

Nie umieszczam weryfikacji w DAO. Oczekuję poprawnych danych z wyższych warstw. W przypadku błędu deleguję na bbdd odpowiedzialność za zapoznanie się z jego treścią.

Następnie następuje walidacja na poziomie biznesowym. Wszystkie walidacje biznesowe koncentrowały się na zachowaniu spójności danych, a nie ich integralności .

Na koniec robię poprzednie walidacje na warstwie kontrolnej. Te związane tylko z taką warstwą.

Wkrótce zobaczysz, które walidacje mają być wdrożone na poziomie biznesowym. Najczęstsze: kontrola id. Ten można łatwo wdrożyć na obu warstwach. Jeśli spodziewasz się, że wielu kontrolerów lub klientów zajmie się twoją warstwą biznesową, zamiast wszędzie powtarzać tę samą weryfikację, będzie to doskonały kandydat do umieszczenia w warstwie biznesowej.

Czasami kontrolery mają swoje własne zasady i warunki, które nie zostaną odtworzone w żadnej innej fasadzie. Następnie jest kandydatem do takiego kontrolera.

Zastanów się, na co się zgadzasz i jeśli chcesz zastosować to dla wszystkich, bez względu na wszystko. Lub jeśli jest to walidacja kontekstowa („Sprawdzam coś, co dzieje się tylko przy określonej elewacji kontrolnej / widokowej).

Laiv
źródło
0

W naszym sklepie Java celowo podzieliliśmy sprawdzanie poprawności widgetów internetowych na trzy osobne operacje.

  1. Podstawowe formatowanie - liczby muszą być liczbami; daty muszą być poprawnymi datami itp. Zwykle ta weryfikacja jest bezpłatna - platforma internetowa zrobi to za Ciebie, gdy powiązasz zawartość widżetu z modelem.
  2. Sprawdzanie poprawności pojedynczego widgetu - data musi być w przeszłości; liczba całkowita musi wynosić od 1 do 100; customerId musi istnieć w bazie danych itp. W większości przypadków należy ona do warstwy kontrolera, ale może wymagać wsparcia z repozytorium danych.
  3. Sprawdzanie poprawności między widgetami - data kasy musi być późniejsza niż data zameldowania; data śmierci nie może być wcześniejsza niż data urodzenia itp. Jest to zdecydowanie walidacja reguł biznesowych. Zwykle umieszczamy to również w warstwie kontrolera, ale możesz chcieć przenieść ją do walidatora biznesowego, aby można go było ponownie wykorzystać.

Jeśli warstwa 1 ulegnie awarii, nie sprawdzamy 2 lub 3. Podobnie, jeśli 1 zakończy się niepowodzeniem, a 2 nie, nie robimy 3. To zatrzymuje generowanie fałszywych komunikatów o błędach.

Pytasz o wartości w wywołaniu REST, a nie o zawartość widżetu, ale obowiązują te same zasady.

kiwiron
źródło
-1

Testowane podejście cieniuje światło, w końcu nie ma kontrolera i musisz wybrać inną opcję. Oczywiście zasady biznesowe powinny znajdować się w jednym miejscu, a to kolejne ograniczenie w waszej rezygnacji.

Hans Poo
źródło