Skip to content

Create REST API

Somkiat Puisungnoen edited this page Apr 1, 2025 · 8 revisions

Create REST Controller

1. Create Users APIs

  • Get all users => GET /users
  • Get user by id => GET /users/{id}

UserController.java

@RestController
public class UserController {

    @GetMapping("/users")
    public List<UserResponse> getAllUsers() {
        List<UserResponse> userResponseList = new ArrayList<>();
        userResponseList.add(new UserResponse(1,"demo 1", 30));
        userResponseList.add(new UserResponse(2,"demo 2", 35));
        return userResponseList;
    }
    
    // Demo of Path Variable
    @GetMapping("/users/{id}")
    public UserResponse getUserById(@PathVariable int id) {
        UserResponse userResponse = new UserResponse(id, "Demo", 40);
        return userResponse;
    }

    // Demo of Request Parameter ?page=1
    @GetMapping("/user")
    public List<UserResponse> getAllUser(@RequestParam(defaultValue = "1") int page) {
        List<UserResponse> userResponseList = new ArrayList<>();
        userResponseList.add(new UserResponse(1, "demo 1", 30));
        userResponseList.add(new UserResponse(2, "demo 2", 35));
        return userResponseList;
    }

    // Custom status code
    @GetMapping("/hello")
    @ResponseStatus(HttpStatus.OK)
    public String sayHi() {
        return "Hello Spring Boot";
    }

}

UserResponse.java

public class UserResponse {
    private int id;
    private String name;
    private int age;

    public UserResponse() {
    }

    public UserResponse(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    // Setter and Getter methods
}

2. Working with HTTP POST => create new user

POST /users

{
    "name": "test",
    "age": 45
}
@PostMapping("/users")
public UserResponse createNewUser(@RequestBody UserRequest newUser) {
    UserResponse newUserResponse = new UserResponse(
            1,
            newUser.getName(),
            newUser.getAge());
    return newUserResponse;
}

Validation rules

name
+ not null , empty
+ ห้ามมีตัวเลข
+ ความยาวไม่เกิน 50
age
+ number only
+ 18-99

Business process/flow (name, age)

  1. Check name (duplicate ?)
    • NameDuplicateException
  2. Create new user in database
  3. Return new user + id

3. Working with HTTP PUT => updateuser

PUT /users/{id}

{
    "name": "test",
    "age": 45
}
@PutMapping("/users/{id}")
public UserResponse updateUser(@RequestBody UserRequest newUser, @PathVariable int id) {
    // TODO
    // 1. find by id
    // 2. found => update user
    // 3. not found => ?? (create ? or throw error)
    UserResponse updatedUserResponse = new UserResponse(
            id,
            newUser.getName(),
            newUser.getAge());
    return updatedUserResponse;
}

4. Working with HTTP DELETE => delete user by id

DELETE /users/{id}

@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable int id) {
    // TODO
}

5. Manage error

GlobalControllerExceptionHandler.java

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(ConversionFailedException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<String> handleConnversion(RuntimeException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
    }
    
    @ExceptionHandler(BookNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ResponseEntity<String> handleBookNotFound(RuntimeException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }
}

UserNotFoundAdvice.java

@ControllerAdvice
public class UserNotFoundAdvice {
    @ResponseBody
    @ExceptionHandler(UserNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    String userNotFoundHandler(UserNotFoundException e) {
        return e.getMessage();
    }
}

UserNotFoundException.java

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(int id) {
        super("Could not find user " + id);
    }
}

6. Validate request

  • Add spring-boot-starter-validation

CreateUserRequest.java

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;

public class CreateUserRequest {

    @NotBlank(message = "Username is required")
    private String username;

    @NotBlank(message = "Password is required")
    @Pattern(regexp = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=!*()]).{8,}$", message = "Password must be 8 characters long and combination of uppercase letters, lowercase letters, numbers, special characters.")
    private String password;
...

UserController.java

RestController
public class UserController {

    @PostMapping("/public/user")
    public UserResponse register(@Valid @RequestBody CreateUserRequest request) {
        // Validate requests

        // Return response
        return new UserResponse();

    }

}

### Add RestControllerAdvice to handle exception
* MethodArgumentNotValidException
* HttpMessageNotReadableException

@RestControllerAdvice public class ValidationExceptionHandler {

@ExceptionHandler(exception = {MethodArgumentNotValidException.class})
public ResponseEntity<?> notValid(MethodArgumentNotValidException ex, HttpServletRequest request) {
    List<String> errors = new ArrayList<>();

    ex.getAllErrors().forEach(err -> errors.add(err.getDefaultMessage()));

    Map<String, List<String>> result = new HashMap<>();
    result.put("errors", errors);

    return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(exception = {HttpMessageNotReadableException.class})
public ResponseEntity<?> badRequest(HttpMessageNotReadableException ex) {
    Map<String, String> result = new HashMap<>();
    result.put("error", ex.getMessage());
    return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
}

}