Robust Validation in the Enterprise Stack
Java Spring Boot remains the backbone of enterprise web development. When building large-scale systems (CRMs, banking portals, or healthcare apps), input validation is critical. While Bean Validation (`@Email`) handles basic syntax, it cannot stop a user from registering with a non-existent email address.
This guide demonstrates how to build a `EmailVerificationService` in Spring Boot that connects to EmailVerifierAPI.com. We will use the modern `java.net.http.HttpClient` available in Java 11+ for non-blocking I/O.
Dependencies
Ensure you have `jackson-databind` in your `pom.xml` or `build.gradle` to parse the JSON response. Most Spring Web starters include this by default.
The Service Implementation
We will create a service that encapsulates the API logic. It builds the request, handles the network call, and maps the JSON response to a Java POJO.
package com.example.demo.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
@Service
public class EmailVerificationService {
private static final String API_KEY = "YOUR_API_KEY"; // Ideally from application.properties
private static final String API_URL = "https://www.emailverifierapi.com/v2/verify";
private final HttpClient httpClient;
private final ObjectMapper objectMapper;
public EmailVerificationService(ObjectMapper objectMapper) {
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.build();
this.objectMapper = objectMapper;
}
public boolean isEmailDeliverable(String email) {
try {
// Build the URI with query parameters
String uri = API_URL + "?api_key=" + API_KEY + "&email=" + email;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
JsonNode root = objectMapper.readTree(response.body());
// Extract fields
String status = root.path("status").asText();
boolean isDisposable = root.path("disposable").asBoolean();
// Business Logic:
// Return true only if Valid AND Not Disposable
return "valid".equalsIgnoreCase(status) && !isDisposable;
} else {
// Handle API errors (4xx, 5xx) - Log and Fail Open or Closed
System.err.println("API Error: " + response.statusCode());
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}Integrating into a Controller
Now you can inject this service into your REST Controller to validate incoming requests.
@PostMapping("/register")
public ResponseEntity<String> registerUser(@RequestBody UserDto user) {
if (!emailVerificationService.isEmailDeliverable(user.getEmail())) {
return ResponseEntity.badRequest().body("Please provide a valid, permanent email address.");
}
// Proceed with registration...
return ResponseEntity.ok("User registered.");
}Handling "Risky" and "Unknown"
The code above implements a strict check (only "valid"). However, in some enterprise contexts, you may encounter "catch-all" domains (which return `risky` or `unknown`).
For a more nuanced approach, you should inspect the `score` field. A score > 0.7 usually indicates a safe-to-send address even if the specific status is uncertain due to server security settings. You can map the JSON response to a dedicated `EmailVerificationResult` class to pass all this data back to your controller for complex decision-making.
Performance Considerations
While this example uses synchronous `httpClient.send`, for high-throughput applications, you should use `httpClient.sendAsync` to prevent blocking your Servlet threads. This allows your Spring Boot application to handle thousands of concurrent verifications without exhausting the thread pool.