{"id":27103004,"url":"https://github.com/yoanesber/spring-boot-validation-using-java-fluent-validator","last_synced_at":"2026-04-28T18:35:02.580Z","repository":{"id":285264020,"uuid":"939981813","full_name":"yoanesber/Spring-Boot-Validation-Using-Java-Fluent-Validator","owner":"yoanesber","description":"This project uses java-fluent-validator to validate API request payloads dynamically, ensuring that data meets business constraints before it is processed or stored in the database.","archived":false,"fork":false,"pushed_at":"2025-03-30T16:49:20.000Z","size":27,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-30T17:33:26.510Z","etag":null,"topics":["fluentvalidation","rest-api","spring-boot","validation"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yoanesber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-27T12:28:23.000Z","updated_at":"2025-03-30T16:49:23.000Z","dependencies_parsed_at":"2025-03-30T17:33:29.035Z","dependency_job_id":"64569bd5-c289-4563-a6af-a8f57f0e0c4a","html_url":"https://github.com/yoanesber/Spring-Boot-Validation-Using-Java-Fluent-Validator","commit_stats":null,"previous_names":["yoanesber/spring-boot-validation-using-java-fluent-validator"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yoanesber/Spring-Boot-Validation-Using-Java-Fluent-Validator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoanesber%2FSpring-Boot-Validation-Using-Java-Fluent-Validator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoanesber%2FSpring-Boot-Validation-Using-Java-Fluent-Validator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoanesber%2FSpring-Boot-Validation-Using-Java-Fluent-Validator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoanesber%2FSpring-Boot-Validation-Using-Java-Fluent-Validator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yoanesber","download_url":"https://codeload.github.com/yoanesber/Spring-Boot-Validation-Using-Java-Fluent-Validator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoanesber%2FSpring-Boot-Validation-Using-Java-Fluent-Validator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32394465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T14:34:11.604Z","status":"ssl_error","status_checked_at":"2026-04-28T14:32:37.009Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fluentvalidation","rest-api","spring-boot","validation"],"created_at":"2025-04-06T16:38:28.659Z","updated_at":"2026-04-28T18:35:02.549Z","avatar_url":"https://github.com/yoanesber.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Validation Using Java Fluent Validator\nThis project uses **Java Fluent Validator** to validate API request payloads dynamically, ensuring that data meets business constraints before it is processed or stored in the database.\n\n## 📖 Overview\nThis project is a Spring Boot REST API designed to manage **Netflix Shows**. It utilizes **Spring Boot**, **Spring Data JPA with Hibernate**, and **PostgreSQL** to perform CRUD operations on Netflix Shows.  \n\nOne of the key aspects of this project is the use of **Java Fluent Validator** to enforce input validation rules **dynamically**. Instead of relying on standard **Java Bean Validation** (annotations like `@NotNull`), this approach allows greater **flexibility, readability, and maintainability** in defining complex validation rules programmatically. By using Fluent Validator, we can ensure that incoming request bodies adhere to the **expected structure and business rules** before persisting data into the database.  \n\n## 🔍 Why Fluent Validator ?\n1. Programmatic \u0026 Flexible  \nUnlike annotations (`@NotNull`, `@Size`, etc.), validation rules can be dynamically modified at runtime. It means that validation rules are not fixed at compile-time but **can be adjusted based on conditions** at runtime. This allows the application to apply different validation rules dynamically depending on user input, API parameters, business logic, or external configurations.  \n\n    Example scenario:  \n    - If `type = \"MOVIE\"`, then durationInMinute must be greater than 0.\n    - If `type = \"TV_SHOW\"`, then durationInMinute should not be validated but seasons must be greater than 0.\n\n```java\npublic class NetflixShowValidator extends AbstractValidator\u003cNetflixShowDto\u003e {\n    @Override\n    public void rules() {\n        // Validate 'type' field (must be either MOVIE or TV_SHOW)\n        ruleFor(NetflixShowDto::getType)\n            .must(type -\u003e type.equals(\"MOVIE\") || type.equals(\"TV_SHOW\"))\n            .withMessage(\"Type must be either MOVIE or TV_SHOW\");\n\n        // Apply different validation rules based on the type\n        ruleFor(NetflixShowDto::getDurationInMinute)\n            .must(duration -\u003e duration \u003e 0)\n            .when(dto -\u003e dto.getType().equals(\"MOVIE\"))  // Only for MOVIE\n            .withMessage(\"Duration must be greater than 0 for movies\");\n\n        ruleFor(NetflixShowDto::getSeasons)\n            .must(seasons -\u003e seasons \u003e 0)\n            .when(dto -\u003e dto.getType().equals(\"TV_SHOW\"))  // Only for TV_SHOW\n            .withMessage(\"Seasons must be greater than 0 for TV shows\");\n    }\n}\n```\n\n2. Better Readability  \nValidation logic is structured in a clear and fluent manner. The validation reads naturally like a sentence. Reads like plain English, unlike traditional `if-else` or annotation-based (`@NotNull`, `@Size`, etc.) validation.  \n\n❌ Without Fluent Validator\n```java\nif (dto.getTitle() == null || dto.getTitle().trim().isEmpty()) {\n    throw new ValidationException(\"Title cannot be empty\");\n}\nif (dto.getReleaseYear() \u003c 1900 || dto.getReleaseYear() \u003e LocalDate.now().getYear()) {\n    throw new ValidationException(\"Invalid release year\");\n}\n```\n\n✅ With Fluent Validator\n```java\nruleFor(NetflixShowDto::getTitle)\n    .notNull().notEmpty().withMessage(\"Title cannot be empty\");\n\nruleFor(NetflixShowDto::getReleaseYear)\n    .must(year -\u003e year \u003e= 1900 \u0026\u0026 year \u003c= LocalDate.now().getYear())\n    .withMessage(\"Invalid release year\");\n\n```\n\n3. Maintainability  \nCentralizes validation logic, making updates easy. If you need to change a rule, you update it in one place instead of modifying multiple files.  \n\n4. Reusable Rules  \nCommon validation logic can be reused across multiple request DTOs.  \n\n5. Extensible  \nCan add custom rules without modifying the existing validation structure.  \n\n6. Improved Error Handling  \nCustom validation messages and logic can be tailored to specific business needs.  \n\n---\n\n\n## 🤖 Tech Stack\nThe technology used in this project are:\n- `Spring Boot Starter Web` – Building RESTful APIs or web applications\n- `Java Fluent Validator` – For advanced request validation\n- `PostgreSQL` – Database for persisting Netflix Shows\n- `Hibernate` – Simplifying database interactions\n- `Lombok` – Reducing boilerplate code\n---\n\n## 🏗️ Project Structure\nThe project follows a layered architecture with the following structure:\n```bash\napi-with-fluent-validator/\n│── src/main/java/com/yoanesber/spring/rest/api_with_fluent_validator/\n│   ├── 📂config/                # Contains configurations for the application\n│   ├── 📂controller/            # Exposes REST API endpoints for handling requests and responses\n│   ├── 📂dto/                   # Data Transfer Objects (DTOs) for request/response payloads\n│   ├── 📂entity/                # Entity classes representing database tables\n│   ├── 📂repository/            # JPA repositories for database access\n│   ├── 📂service/               # Business logic layer\n│   │   ├── 📂impl/              # Implementation of services\n│   ├── 📂validator/             # Contains custom validation logic using Fluent Validator to enforce constraints on API request payloads\n``` \n---\n\n## ⚙ Environment Configuration\nConfiguration values are stored in `.env.development` and referenced in `application.properties`.  \nExample `.env.development` file content:  \n```properties\n# Application properties\nAPP_PORT=8081\nSPRING_PROFILES_ACTIVE=development\n \n# Database properties\nSPRING_DATASOURCE_PORT=5432\nSPRING_DATASOURCE_USERNAME=your_username\nSPRING_DATASOURCE_PASSWORD=your_password \nSPRING_DATASOURCE_DB=your_db\nSPRING_DATASOURCE_SCHEMA=your_schema\n```\n\nExample `application.properties` file content:  \n```properties\n# Application properties\nspring.application.name=api-with-fluent-validator\nserver.port=${APP_PORT}\nspring.profiles.active=${SPRING_PROFILES_ACTIVE}\n\n## datasource\nspring.datasource.url=jdbc:postgresql://localhost:${SPRING_DATASOURCE_PORT}/${SPRING_DATASOURCE_DB}?currentSchema=${SPRING_DATASOURCE_SCHEMA}\nspring.datasource.username=${SPRING_DATASOURCE_USERNAME}\nspring.datasource.password=${SPRING_DATASOURCE_PASSWORD}\n```\n---\n\n## 💾 Database Schema (DDL – PostgreSQL)\nThe project uses PostgreSQL as its database, with a structured schema to store Netflix show data efficiently. Below is the DDL (Data Definition Language) used to create the database schema.\n\n```sql\nCREATE SCHEMA your_schema;\n\nCREATE SEQUENCE your_schema.id_netflix_shows_seq\nSTART WITH 1\nINCREMENT BY 1\nNO MINVALUE\nNO MAXVALUE\nCACHE 1;\n\nCREATE TABLE IF NOT EXISTS your_schema.netflix_shows (\n\tid int8 NOT NULL DEFAULT nextval('your_schema.id_netflix_shows_seq'::regclass),\n\t\"type\" varchar(7) NOT NULL,\n\ttitle text NOT NULL,\n\tdirector text NULL,\n\tcast_members text NULL,\n\tcountry varchar(60) NOT NULL,\n\tdate_added date NOT NULL,\n\trelease_year int4 NOT NULL,\n\trating int4 NULL,\n\tduration_in_minute int4 NULL,\n\tlisted_in text NULL,\n\tdescription text NULL,\n\tCONSTRAINT netflix_shows_pkey PRIMARY KEY (id),\n\tCONSTRAINT netflix_shows_type_check CHECK (((type)::text = ANY (ARRAY[('MOVIE'::character varying)::text, ('TV_SHOW'::character varying)::text])))\n);\n```\n---\n\n## 🛠️ Installation \u0026 Setup\nA step by step series of examples that tell you how to get a development env running.\n1. Clone the repository\n```bash\ngit clone https://github.com/yoanesber/Spring-Boot-Validation-Using-Java-Fluent-Validator.git\ncd Spring-Boot-Validation-Using-Java-Fluent-Validator\n```\n\n2. Set up PostgreSQL\n- Run the provided DDL script to set up the database schema\n- Configure the connection in `.env.development` file:\n```properties\n# Database properties\nSPRING_DATASOURCE_PORT=5432\nSPRING_DATASOURCE_USERNAME=your_username\nSPRING_DATASOURCE_PASSWORD=your_password\nSPRING_DATASOURCE_DB=your_db\nSPRING_DATASOURCE_SCHEMA=your_schema\n```\n\n3. Run the application locally\nMake sure PostgreSQL is running, then execute:  \n```bash\nmvn spring-boot:run\n```\n\n4. Now, application is available at:  \n```bash\nhttp://localhost:8081/ \n```\n\nYou can test the API using: Postman (Desktop/Web version) or cURL\n\n---\n\n## 🌐 API Endpoints\nThe REST API provides a set of endpoints to manage Netflix shows, allowing clients to perform CRUD operations (Create, Read, Update, Delete). Each endpoint follows RESTful principles and accepts/returns JSON data. Below is a list of available endpoints along with sample requests.  \n\n- `GET` http://localhost:8081/api/v1/netflix-shows - Retrieve all Netflix Shows.  \n\n- `GET` http://localhost:8081/api/v1/netflix-shows/1 - Retrieve a specific Netflix Show by ID.  \n\n**Successful Response:**\n```json\n{\n    \"statusCode\": 200,\n    \"timestamp\": \"2025-02-27T21:31:56.0479465\",\n    \"message\": \"NetflixShows retrieved successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"showType\": \"MOVIE\",\n        \"title\": \"Sankofa\",\n        \"director\": \"Haile Gerima\",\n        \"castMembers\": \"Kofi Ghanaba, Oyafunmike Ogunlano, Alexandra Duah, Nick Medley, Mutabaruka, Afemo Omilami, Reggie Carter, Mzuri, Oliver\",\n        \"country\": \"United States\",\n        \"dateAdded\": \"2021-09-24\",\n        \"releaseYear\": 2024,\n        \"rating\": 10,\n        \"durationInMinute\": 90,\n        \"listedIn\": \"Comedies\",\n        \"description\": \"A woman adjusting to life after a loss contends with a feisty bird that's taken over her garden — and a husband who's struggling to find a way forward.\"\n    }\n}\n```\n\n- `POST` http://localhost:8081/api/v1/netflix-shows - Create a new Netflix Show.  \n\n**Request Body:**\n```json\n{\n    \"showType\":\"TV_SHOW\",\n    \"title\":\"The Smart Money Woman\",\n    \"director\":\"Bunmi Ajakaiye\",\n    \"castMembers\":\"Osas Ighodaro, Ini Dima-Okojie, Kemi Lala Akindoju, Toni Tones, Ebenezer Eno, Eso Okolocha DIke, Patrick Diabuah, Karibi Fubara, Temisan Emmanuel, Timini Egbuson\",\n    \"country\":\"India\",\n    \"dateAdded\":\"2021-09-16\",\n    \"releaseYear\":2020,\n    \"rating\":5,\n    \"durationInMinute\":90,\n    \"listedIn\":\"International TV Shows, Romantic TV Shows, TV Comedies\",\n    \"description\":\"Five glamorous millennials strive for success as they juggle careers, finances, love and friendships. Based on Arese Ugwu's 2016 best-selling novel.\"\n}\n```\n\n**Successful Response:**\n```json\n{\n    \"statusCode\": 201,\n    \"timestamp\": \"2025-02-27T21:32:43.3093492\",\n    \"message\": \"NetflixShows created successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"showType\": \"TV_SHOW\",\n        \"title\": \"The Smart Money Woman\",\n        \"director\": \"Bunmi Ajakaiye\",\n        \"castMembers\": \"Osas Ighodaro, Ini Dima-Okojie, Kemi Lala Akindoju, Toni Tones, Ebenezer Eno, Eso Okolocha DIke, Patrick Diabuah, Karibi Fubara, Temisan Emmanuel, Timini Egbuson\",\n        \"country\": \"India\",\n        \"dateAdded\": \"2021-09-16\",\n        \"releaseYear\": 2020,\n        \"rating\": 5,\n        \"durationInMinute\": 90,\n        \"listedIn\": \"International TV Shows, Romantic TV Shows, TV Comedies\",\n        \"description\": \"Five glamorous millennials strive for success as they juggle careers, finances, love and friendships. Based on Arese Ugwu's 2016 best-selling novel.\"\n    }\n}\n```\n\nWhen sending an **invalid JSON body**, the API will return a `400 Bad Request` response with validation error details.  \n\n**Request Body:**\n```json\n{\n    \"showType\":\"TV Show\",\n    \"title\":\"King of Boys: The Return of the King ¶\",\n    \"director\":\"Kemi Adetiba\",\n    \"castMembers\":\"Sola Sobowale, Toni Tones, Richard Mofe-Damijo, Efa Iwara, Titi Kuti, Tobechukwu \\\"iLLbliss\\\" Ejiofor, Remilekun \\\"Reminisce\\\" Safaru, Charles  \\\"Charly Boy\\\" Oputa, Nse Ikpe-Etim, Keppy Ekpenyong Bassey, Bimbo Manuel, Akin Lewis, Lord Frank, Osas Ighodaro, Taiwo Ajai-Lycett, Paul Sambo\",\n    \"country\":\"United States, The United Kingdom of Great Britain and Northern Ireland ¶\",\n    \"dateAdded\":\"2021-08-27\",\n    \"releaseYear\":2021,\n    \"rating\":70,\n    \"durationInMinute\":90,\n    \"listedIn\":\"Crime TV Shows, International TV Shows, TV Dramas\",\n    \"description\":\"Alhaja Eniola Salami starts anew and sets her sights on a different position of power, fueled by revenge, regret and ruthlessness.\"\n}\n```\n\nFor the request body above, the response obtained is as follows:  \n```json\n{\n    \"statusCode\": 400,\n    \"timestamp\": \"2025-02-27T21:46:23.6795329\",\n    \"message\": \"Validation failed. Please check your input.\",\n    \"data\": {\n        \"Country\": [\n            \"Country must contain only printable ASCII characters\",\n            \"Country must be less than or equal to 60 character length\"\n        ],\n        \"Rating\": [\n            \"Rating must be between 1 and 10\"\n        ],\n        \"ShowType\": [\n            \"ShowType must be either MOVIE or TV_SHOW\"\n        ],\n        \"Title\": [\n            \"Title must contain only printable ASCII characters\"\n        ]\n    }\n}\n```\n\n**Note**: This response clearly indicates which fields failed validation and provides meaningful error messages for better debugging and user experience.  \n\n- `PUT` http://localhost:8081/api/v1/netflix-shows/1 - Update an existing Netflix Show.  \n\n**Request Body:**\n```json\n{\n    \"showType\": \"MOVIE\",\n    \"title\": \"Sankofa\",\n    \"director\": \"Haile Gerima\",\n    \"castMembers\": \"Kofi Ghanaba, Oyafunmike Ogunlano, Alexandra Duah, Nick Medley, Mutabaruka, Afemo Omilami, Reggie Carter, Mzuri, Oliver\",\n    \"country\": \"United States\",\n    \"dateAdded\": \"2021-09-24\",\n    \"releaseYear\": 2024,\n    \"rating\": 10,\n    \"durationInMinute\": 90,\n    \"listedIn\": \"Drama\",\n    \"description\": \"A woman adjusting to life after a loss contends with a feisty bird that's taken over her garden — and a husband who's struggling to find a way forward.\"\n}\n```\n\n**Successful Response:**\n```json\n{\n    \"statusCode\": 200,\n    \"timestamp\": \"2025-02-27T21:34:43.8536126\",\n    \"message\": \"NetflixShows updated successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"showType\": \"MOVIE\",\n        \"title\": \"Sankofa\",\n        \"director\": \"Haile Gerima\",\n        \"castMembers\": \"Kofi Ghanaba, Oyafunmike Ogunlano, Alexandra Duah, Nick Medley, Mutabaruka, Afemo Omilami, Reggie Carter, Mzuri, Oliver\",\n        \"country\": \"United States\",\n        \"dateAdded\": \"2021-09-24\",\n        \"releaseYear\": 2024,\n        \"rating\": 10,\n        \"durationInMinute\": 90,\n        \"listedIn\": \"Drama\",\n        \"description\": \"A woman adjusting to life after a loss contends with a feisty bird that's taken over her garden — and a husband who's struggling to find a way forward.\"\n    }\n}\n```\n\n- `DELETE` http://localhost:8081/api/v1/netflix-shows/1 - Delete a Netflix Show.  \n\n**Successful Response:**\n```json\n{\n    \"statusCode\": 200,\n    \"timestamp\": \"2025-02-27T21:35:17.0110773\",\n    \"message\": \"NetflixShows deleted successfully\",\n    \"data\": null\n}\n```\n---","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoanesber%2Fspring-boot-validation-using-java-fluent-validator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoanesber%2Fspring-boot-validation-using-java-fluent-validator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoanesber%2Fspring-boot-validation-using-java-fluent-validator/lists"}