In welcher Ebene soll sich die Validierung befinden?


18

Ich erstelle eine Rest-API mit Spring Boot und verwende die Ruhezustandsüberprüfung, um Anforderungseingaben zu überprüfen.

Ich benötige aber auch andere Arten der Validierung, zum Beispiel, wenn Aktualisierungsdaten überprüft werden müssen. Wenn die Firmen-ID nicht vorhanden ist, möchte ich eine benutzerdefinierte Ausnahme auslösen.

Sollte sich diese Validierung auf der Service-Ebene oder der Controller-Ebene befinden?

Serviceschicht:

 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);
}

Controller-Schicht:

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);
}

Antworten:


8

Sowohl die Controller-Schicht als auch die Service-Schicht legen bestimmte Schnittstellen offen. Schnittstellen definieren Verträge darüber, wie die Schnittstelle verwendet werden soll. Vertrag bedeutet normalerweise, welche Argumente (und ihre Typen und Werte) erwartet werden, welche Ausnahmen geworfen werden können, welche Nebenwirkungen auftreten usw.

Ihre Validierung besteht nun im Wesentlichen in der Durchsetzung des Vertrags über die Aktualisierung () der Controller-Methode und der Aktualisierung () der Service-Schicht. Beide haben einen sehr ähnlichen Vertrag, daher wäre es natürlich, wenn die Validierung (Durchsetzung des Vertrags) ebenfalls üblich wäre.

Eine Möglichkeit, dies zu tun, besteht darin, die Validierung dieses Vertrags zu trennen und in beiden Ebenen aufrufen zu lassen. Dies ist in der Regel am klarsten: Jede Klasse / Methode setzt ihren eigenen Vertrag durch, ist jedoch häufig aus Gründen der Leistung (Zugriff auf die Datenbank) oder aus anderen Gründen unpraktisch.

Eine andere Möglichkeit besteht darin, diese Validierung an die Serviceschicht zu delegieren und gleichzeitig das Verhalten im Fall einer fehlgeschlagenen Validierung im Serviceschichtvertrag explizit zu definieren. Die Service-Schicht gibt normalerweise einen allgemeinen Validierungsfehler (oder eine Ausnahmebedingung) zurück, und die Controller-Schicht möchte auf bestimmte Weise auf den Fehler reagieren. In diesem Fall geben wir 400 Bad request zurück, um zu signalisieren, dass die eingehende Anforderung ungültig war.

Bei diesem Entwurf besteht die Gefahr einer zu starken Kopplung zwischen der Geschäftslogik in der Serviceschicht (die recht allgemein sein sollte) und dem Controller (der die Integrationslogik handhabt).

Wie auch immer, dies ist eine ziemlich kontroverse Frage und 100 Personen werden mit 100 Antworten antworten. Dies ist nur meine Einstellung dazu.


1

Die Eingabe sollte in der Serviceebene überprüft werden.

Und "ID kann nicht gefunden werden" ist eine logische Fehlerbedingung. Also sollte aus Controller-Ebene geworfen werden.

Dies hängt wiederum von Ihrer Schichtung / Ihrem Design ab.
Was soll eine Service-Schicht tun und was wird von der Controller-Schicht erwartet?


Eine Antwort sollte keine zusätzliche Klärung der Frage sein. Wenn die Frage geklärt werden muss, sollte sie kommentiert und möglicherweise zur Schließung vorgemerkt werden, wenn sie zu unklar ist. Ja, mir ist klar, dass Sie für keine dieser Aktionen den Ruf haben.

"Eingabeprüfung" ist nicht eindeutig. Ich könnte beispielsweise ein Erforderliches Attribut in ein Feld einfügen, um anzuzeigen, dass es ausgefüllt werden muss, aber ich könnte auch ein komplexes benutzerdefiniertes Attribut einfügen, das beispielsweise prüft, ob ein Feldwert größer als ein anderer ist. IMHO "riecht" die Compare-Validierung viel mehr nach Business-Service-Schicht als nach Controller-Schicht.
JustAMartin

1

Ruhezustandsüberprüfungen sind Überprüfungen der Integrität der Daten. Um RuntimeExceptions von bbdd zu vermeiden. Es sind so ziemlich die gleichen Validierungen, die Sie mit Constrains steuern sollten . Da nur die Business - Schicht sollte Fütterung werden die Persistenz - Schicht, können Sie (oder auch nicht, bis zu Ihnen) vertrauen auf die Richtigkeit der Daten , die von Ihrer Business - Schicht kommt

Ich schreibe keine Validierungen in DAOs. Ich erwarte gültige Daten aus den oberen Schichten. Im Falle eines Fehlers delegiere ich die Verantwortung für die Kenntnis des Inhalts an den BBDD.

Dann folgen Validierungen auf der Business-Ebene. Bei allen Geschäftsvalidierungen stand die Kohärenz der Daten im Vordergrund, nicht deren Integrität .

Schließlich mache ich vorherige Überprüfungen auf der Kontrollebene. Diejenigen, die nur mit einer solchen Schicht zusammenhängen.

Sie werden bald sehen, welche Validierungen in der Business-Schicht implementiert werden sollen. Am häufigsten: ID-Kontrolle. Dieser kann problemlos auf beiden Ebenen implementiert werden. Wenn Sie davon ausgehen, dass viele Controller oder Clients Ihre Business-Schicht verbrauchen, ist dies ein hervorragender Kandidat für die Business-Schicht, anstatt überall dieselbe Validierung zu wiederholen.

Manchmal haben Controller ihre eigenen Regeln und Bedingungen, die in keiner anderen Fassade reproduziert werden können. Dann ist es ein Kandidat, in eine solche Steuerung eingesetzt zu werden.

Überlegen Sie, wofür Sie validieren und ob Sie es für alle anwenden möchten, egal was passiert. Oder wenn es sich um eine kontextbezogene Validierung handelt ("Ich validiere etwas, das nur an einer bestimmten Steuerungs- / Ansichtsfassade passiert).


0

In unserem Java-Shop haben wir die Überprüfung von Web-Widgets absichtlich auf drei separate Vorgänge aufgeteilt.

  1. Grundlegende Formatierung - Zahlen müssen Zahlen sein. Daten müssen gültige Daten usw. sein. In der Regel ist diese Validierung kostenlos - das Web-Framework übernimmt dies für Sie, wenn Sie Widget-Inhalte an das Modell binden.
  2. Einzelwidget-Validierung - Datum muss in der Vergangenheit liegen; eine ganze Zahl muss zwischen 1 und 100 liegen; customerId muss in der Datenbank usw. vorhanden sein. Dies gehört in den meisten Fällen in die Controllerschicht, benötigt jedoch möglicherweise Unterstützung vom Daten-Repository.
  3. Widgetübergreifende Validierung - Das Abreisedatum muss nach dem Eincheckdatum liegen. Das Todesdatum darf nicht vor dem Geburtsdatum liegen. Dies ist definitiv eine Überprüfung der Geschäftsregeln. Wir tendieren dazu, dies auch in der Controller-Ebene zu platzieren, aber Sie können es in einen Business Validator verschieben, damit es wiederverwendet werden kann.

Wenn Schicht 1 ausfällt, werden 2 oder 3 nicht überprüft. Wenn 1 erfolgreich ist und 2 fehlschlägt, wird 3 nicht überprüft. Dadurch werden keine falschen Fehlermeldungen generiert.

Sie fragen bei einem REST-Aufruf nach Werten und nicht nach Widget-Inhalten, es gelten jedoch dieselben Prinzipien.


-1

Probefahrten schatten ein Licht auf diese, schließlich gibt es keinen Controller und Sie müssen eine andere Option wählen. Offensichtlich sollten sich die Geschäftsregeln an einer Stelle befinden, und dies ist eine weitere Einschränkung in Ihrer Entscheidung.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.