Walidacja danych wejściowych jest ważnym procesem w naszych aplikacjach/usługach, umożliwia uniknięcie błędów wynikających z niepoprawnych wartości. Istnieje kilka sposób na implementacje walidacji w projektach. Najbrzydszym rozwiązaniem jest utworzenie długich litanii if-ów weryfikujących wartości uzyskane na wejściu akcji kontrolera. W ASP.NET najpowszechniejszą metodą walidacji danych wejściowych jest wykorzystanie wbudowanego mechanizmu walidacji za pomocą atrybutów (Data Annotations). Powyższe rozwiązanie dobrze sprawdza się przy prostych walidacjach, przy bardziej złożonych warto poszukać innej alternatywy. W tym artykule pokażę inne podejście do walidacji, czyli wykorzystam bibliotekę FluentValidation, która umożliwia definiowanie prostych oraz zaawansowanych reguł walidacji z wykorzystaniem wyrażeń lambda. Wykorzystanie FluentValidation pozwala wydzielić logikę walidacji z klasy modelu do klasy Validator. Definicja walidacji z wykorzystaniem interfejsu fluent poprawia czytelność kodu. Reguły walidacji są także łatwe do zweryfikowania testami jednostkowymi.

Integracja FluentValidation z ASP.NET Core Web API

W celu wykorzystania biblioteki w projekcie ASP.NET Core Web API należy zainstalować paczkę z NuGet.

Po dodaniu biblioteki do projektu należy skonfigurować FluentValidation w klasie Startup, poprzez wywołanie metody AddFluentValidation z namespace FluentValidation.AspNetCore. W celu wykrycia przez API walidatorów,  należy wykonać rejestracje walidatorów w metodzie ConfigureServices. Rejestracje można wykonać poprzez wywołanie metody AddTransient dla każdego walidatora, lub poprzez automatyczną rejestracje wszystkich walidatorów z assembly.

Przykład walidacji

Po wymaganej konfiguracji projektu przejdźmy do przykładu stworzonego na potrzeby artykułu. Wykorzystując bibliotekę FluentValidation zostanie sprawdzona poprawność obiektu, który jest przekazywany do akcji kontrolera. Dla prezentacji możliwości biblioteki załóżmy, że mamy API, które umożliwia dodanie obrazu do zasobu np. kolekcji, bazy danych. Na potrzeby wpisu nie interesuje nas implementacja interfejsu IPictureService, potraktujmy ją, jako czarną skrzynkę. Najpierw zdefiniujmy przykładowy model PictureForCreation.

Kolejnym krokiem jest zdefiniowanie klasy Validator, która dziedziczy po abstrakcyjnej klasie AbstactValidator<T>, gdzie T jest typem modelu, dla którego definiowane są reguły walidacji. Reguły walidacji powinny zostać zdefiniowane w konstruktorze walidatora. W celu zdefiniowania reguły walidacji dla właściwości modelu wywoływana jest metoda RuleFor.

PicturesController walidacja modelu zostanie wywołana dla żądania typu POST, którego zadaniem jest dodanie nowego obrazu do zasobów. Na wejście podajemy model typu PictureForCreation, po stronie PictureService operujemy modelem typu Picture, a z API zwracamy obiekt DTO (PictureDto). Gdy dane nie przejdą walidacji zostanie zwrócony kod odpowiedzi HTTP 400 (Bad Request), w przypadku powodzenia otrzymamy kod 201 (Created). Kontroler sprawdza czy model jest poprawny i umieszcza ewentualne błędy w obiekcie ModelState.  Poniżej zaprezentowano implementacje kontrolera PicturesController.

W celu weryfikacji czy walidacji działa poprawnie zostało wykonane żądanie dodanie nowego obrazu, gdzie tytuł i opis zawierają ten sam ciąg znaków. W wyniku walidacji w narzędziu Postman otrzymałem kod odpowiedzi HTTP 400 z odpowiednim komunikatem.

Create picture

W przypadku poprawnego modelu otrzymamy kod odpowiedzi HTTP 201.

Created Picture

Podsumowanie

Artykuł przedstawił jak biblioteka FluentValidation zapewnia czytelną implementacje reguł walidacji po za klasą modelu. Mam nadzieje, że powyższym wpisem przekonałem was do spróbowania swoich sił z FluentValidation.