A lightweight Java library for unified API response handling with comprehensive error management and best practices.
- 🚀 Unified Response Format: Standardized API response structure
- 🛡️ Error Code Management: Centralized error code definitions
- đź”§ Utility Methods: Rich helper methods for response creation
- 📝 Exception Handling: Smart exception with error codes
- 🎯 Type Safety: Generic support for any data type
- 📦 Lightweight: Minimal dependencies, easy to integrate
- Java generic implementation version of Golang with multiple return values (including error and data)
- Result entity wrapper class, including return value status, object, error information, etc
origin/master
<dependency>
<groupId>io.wangxin</groupId>
<artifactId>smart-result</artifactId>
<version>1.0.0</version>
</dependency>
Unified api return result entity object
// Success response with data
User user = new User("John", "[email protected]");
Result<User> result = ResultUtils.wrapSuccess(user);
// Success response without data
Result<Void> result = ResultUtils.wrapSuccess();
// Error response
Result<Void> result = ResultUtils.wrapFailure(400, "Bad Request");
{
"code": 0,
"message": "",
"data": {
"name": "John",
"email": "[email protected]"
}
}
Unified API response wrapper class with generic support.
Key Methods:
isSuccess()
: Check if response is successfulgetData()
: Get response datagetCode()
: Get response codegetMessage()
: Get response message
Abstract interface for error code definitions.
Default Error Codes:
SYSTEM_EXCEPTION_CODE
: 500 (System Exception)OBJECT_NOT_FOUND
: 404 (Object Not Found)
Utility class with rich methods for response creation and error handling.
Custom exception class that integrates with error codes.
public enum UserErrorCode implements IFailCode {
USER_NOT_FOUND(1001, "User not found: %s"),
INVALID_EMAIL(1002, "Invalid email format: %s"),
DUPLICATE_USER(1003, "User already exists: %s");
private final int value;
private final String desc;
UserErrorCode(int value, String desc) {
this.value = value;
this.desc = desc;
}
@Override
public int getValue() {
return value;
}
@Override
public String getDesc() {
return desc;
}
}
@Service
public class UserService {
public Result<User> getUserById(Long id) {
try {
User user = userRepository.findById(id);
if (user == null) {
return ResultUtils.wrapFailure(UserErrorCode.USER_NOT_FOUND, id.toString());
}
return ResultUtils.wrapSuccess(user);
} catch (Exception e) {
return ResultUtils.wrapException(e);
}
}
public Result<User> createUser(UserCreateRequest request) {
try {
if (userRepository.existsByEmail(request.getEmail())) {
return ResultUtils.wrapFailure(UserErrorCode.DUPLICATE_USER, request.getEmail());
}
User user = new User(request.getName(), request.getEmail());
User savedUser = userRepository.save(user);
return ResultUtils.wrapSuccess(savedUser);
} catch (Exception e) {
return ResultUtils.wrapException(e);
}
}
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public Result<User> getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
@PostMapping
public Result<User> createUser(@RequestBody UserCreateRequest request) {
return userService.createUser(request);
}
}
public class UserNotFoundException extends SmartException {
public UserNotFoundException(Long userId) {
super(UserErrorCode.USER_NOT_FOUND, userId.toString());
}
}
// Usage in service
public Result<User> getUserById(Long id) {
User user = userRepository.findById(id);
if (user == null) {
throw new UserNotFoundException(id);
}
return ResultUtils.wrapSuccess(user);
}
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(SmartException.class)
public ResponseEntity<Result<Void>> handleSmartException(SmartException e) {
Result<Void> result = ResultUtils.wrapFailure(e.getCode(), e.getDesc());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Result<Void>> handleGenericException(Exception e) {
Result<Void> result = ResultUtils.wrapException(e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
public class ResponseValidator {
public static <T> boolean isValid(Result<T> result) {
return result != null && result.isSuccess();
}
public static <T> T getDataOrThrow(Result<T> result) {
if (!isValid(result)) {
throw new IllegalStateException("Invalid result: " + result.getMessage());
}
return result.getData();
}
}
// Usage
Result<User> result = userService.getUserById(1L);
if (ResponseValidator.isValid(result)) {
User user = result.getData();
// Process user
}
@SpringBootTest
class UserServiceTest {
@Test
void getUserById_Success() {
// Given
Long userId = 1L;
User expectedUser = new User("John", "[email protected]");
// When
Result<User> result = userService.getUserById(userId);
// Then
assertTrue(result.isSuccess());
assertEquals(expectedUser, result.getData());
assertEquals(0, result.getCode());
}
@Test
void getUserById_NotFound() {
// Given
Long userId = 999L;
// When
Result<User> result = userService.getUserById(userId);
// Then
assertFalse(result.isSuccess());
assertEquals(UserErrorCode.USER_NOT_FOUND.getValue(), result.getCode());
assertTrue(result.getMessage().contains("999"));
}
}
- 0: Success
- 1-999: System level errors
- 1000-1999: User/authentication errors
- 2000-2999: Business logic errors
- 3000-3999: Data validation errors
- 4000-4999: External service errors
- 5000+: Custom application errors
Before:
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("data", user);
response.put("message", "Success");
After:
Result<User> result = ResultUtils.wrapSuccess(user);
Before:
try {
// business logic
} catch (Exception e) {
logger.error("Error occurred", e);
return ResponseEntity.status(500).body("Internal Server Error");
}
After:
try {
// business logic
} catch (Exception e) {
return ResultUtils.wrapException(e);
}
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
If you have any questions or need help, please open an issue on GitHub or contact the maintainers.