Skip to content

Commit 247845a

Browse files
committed
feat(dummy_paginated: add pagination for fetch and save usecase
1 parent 928bd24 commit 247845a

15 files changed

Lines changed: 326 additions & 71 deletions

File tree

src/main/java/com/xpeho/spring_boot_java_random_user/data/models/api/RandomUserResponse.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,44 @@ public class RandomUserResponse {
88
@SerializedName("users")
99
private List<RandomUserResultDAO> users;
1010

11+
@SerializedName("total")
12+
private int total;
13+
14+
@SerializedName("skip")
15+
private int skip;
16+
17+
@SerializedName("limit")
18+
private int limit;
19+
1120
public List<RandomUserResultDAO> getUsers() {
1221
return users;
1322
}
1423

1524
public void setUsers(List<RandomUserResultDAO> users) {
1625
this.users = users;
1726
}
27+
28+
public int getTotal() {
29+
return total;
30+
}
31+
32+
public void setTotal(int total) {
33+
this.total = total;
34+
}
35+
36+
public int getSkip() {
37+
return skip;
38+
}
39+
40+
public void setSkip(int skip) {
41+
this.skip = skip;
42+
}
43+
44+
public int getLimit() {
45+
return limit;
46+
}
47+
48+
public void setLimit(int limit) {
49+
this.limit = limit;
50+
}
1851
}

src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/RandomUserApi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77

88
public interface RandomUserApi {
99
@GET("/users")
10-
Call<RandomUserResponse> getRandomUsers(@Query("limit") int limit);
10+
Call<RandomUserResponse> getRandomUsers(@Query("limit") int limit, @Query("skip") int skip);
1111
}

src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/RandomUserProviderImpl.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.xpeho.spring_boot_java_random_user.data.models.api.RandomUserResultDAO;
66
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
77
import com.xpeho.spring_boot_java_random_user.domain.services.RandomUserProvider;
8+
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
89
import org.springframework.stereotype.Service;
910
import retrofit2.Response;
1011

@@ -22,17 +23,21 @@ public RandomUserProviderImpl(RandomUserApi randomUserApi, UserConverter userCon
2223
}
2324

2425
@Override
25-
public List<UserEntity> fetchRandomUsers(int count) throws IOException {
26-
Response<RandomUserResponse> response = randomUserApi.getRandomUsers(count).execute();
26+
public UserResponseDTO fetchRandomUsers(int page, int size) throws IOException {
27+
// Convert 1-based page index to 0-based skip offset
28+
int skip = (page - 1) * size;
29+
Response<RandomUserResponse> response = randomUserApi.getRandomUsers(size, skip).execute();
2730
if (!response.isSuccessful() || response.body() == null) {
2831
throw new IOException("Failed to fetch users: " + response.code());
2932
}
30-
List<RandomUserResultDAO> users = response.body().getUsers();
33+
RandomUserResponse body = response.body();
34+
List<RandomUserResultDAO> users = body.getUsers();
3135
if (users == null) {
3236
throw new IOException("Failed to parse users from response");
3337
}
34-
return users.stream()
38+
List<UserEntity> entities = users.stream()
3539
.map(userConverter::fromApiModel)
3640
.toList();
41+
return new UserResponseDTO(entities, body.getTotal(), body.getSkip(), body.getLimit());
3742
}
3843
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.xpeho.spring_boot_java_random_user.domain.exceptions;
2+
3+
public class InvalidPaginationException extends RuntimeException {
4+
public InvalidPaginationException(String message) {
5+
super(message);
6+
}
7+
8+
}
9+
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package com.xpeho.spring_boot_java_random_user.domain.services;
22

3-
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
3+
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
44

55
import java.io.IOException;
6-
import java.util.List;
76

87
public interface RandomUserProvider {
9-
List<UserEntity> fetchRandomUsers(int count) throws IOException;
10-
8+
UserResponseDTO fetchRandomUsers(int page, int size) throws IOException;
119
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package com.xpeho.spring_boot_java_random_user.domain.usecases;
22

3-
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
43
import com.xpeho.spring_boot_java_random_user.domain.services.RandomUserProvider;
54
import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
5+
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
66
import org.springframework.stereotype.Service;
77

88
import java.io.IOException;
9-
import java.util.List;
109

1110
@Service
1211
public class FetchAndSaveRandomUsersUseCase {
@@ -19,8 +18,9 @@ public FetchAndSaveRandomUsersUseCase(UserService userService, RandomUserProvide
1918
this.randomUserProvider = randomUserProvider;
2019
}
2120

22-
public List<UserEntity> execute(int count) throws IOException {
23-
List<UserEntity> users = randomUserProvider.fetchRandomUsers(count);
24-
return userService.saveAll(users);
21+
public UserResponseDTO execute(int page, int size) throws IOException {
22+
UserResponseDTO response = randomUserProvider.fetchRandomUsers(page, size);
23+
userService.saveAll(response.getData());
24+
return response;
2525
}
2626
}

src/main/java/com/xpeho/spring_boot_java_random_user/presentation/controllers/UserController.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
44
import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
5+
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
56
import io.swagger.v3.oas.annotations.Operation;
67
import io.swagger.v3.oas.annotations.Parameter;
78
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -11,7 +12,6 @@
1112
import org.springframework.http.ResponseEntity;
1213
import org.springframework.web.bind.annotation.*;
1314

14-
import java.util.List;
1515

1616

1717
@RequestMapping("/random-users")
@@ -21,19 +21,23 @@ public interface UserController {
2121
@GetMapping("")
2222
@Operation(
2323
summary = "Get random users",
24-
description = "Fetches a list of random users from the external API and saves them to the database.",
24+
description = "Fetches a paginated list of random users from the external API and saves them to the database.",
2525
parameters = {
26-
@Parameter(name = "count", description = "Number of users to generate (max 5000)", example = "500")
26+
@Parameter(name = "page", description = "Page number", example = "1"),
27+
@Parameter(name = "size", description = "Number of users per page (max 30)", example = "10")
2728
}
2829
)
2930
@ApiResponse(responseCode = "200", description = "List of users successfully fetched and saved")
3031
@ApiResponse(responseCode = "500", description = "Internal server error")
3132
@ApiResponse(responseCode = "503", description = "External service unavailable")
32-
ResponseEntity<List<UserEntity>> getRandomUsers(
33-
@RequestParam(defaultValue = "500")
33+
ResponseEntity<UserResponseDTO> getRandomUsers(
34+
@RequestParam(defaultValue = "1")
3435
@Min(1)
35-
@Max(5000)
36-
int count
36+
int page,
37+
@RequestParam(defaultValue = "10")
38+
@Min(1)
39+
@Max(30)
40+
int size
3741
);
3842

3943
@GetMapping("/{id}")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.xpeho.spring_boot_java_random_user.presentation.dto;
2+
3+
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
4+
5+
import java.util.List;
6+
7+
public class UserResponseDTO {
8+
private List<UserEntity> data;
9+
private int total;
10+
private int skip;
11+
private int limit;
12+
13+
public UserResponseDTO(List<UserEntity> data, int total, int skip, int limit) {
14+
this.data = data;
15+
this.total = total;
16+
this.skip = skip;
17+
this.limit = limit;
18+
}
19+
20+
public List<UserEntity> getData() {
21+
return data;
22+
}
23+
24+
public int getTotal() {
25+
return total;
26+
}
27+
28+
public int getSkip() {
29+
return skip;
30+
}
31+
32+
public int getLimit() {
33+
return limit;
34+
}
35+
}
36+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.xpeho.spring_boot_java_random_user.presentation.exceptions;
2+
3+
public record ErrorResponse(String error, String message, int status) {
4+
}
5+
6+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.xpeho.spring_boot_java_random_user.presentation.exceptions;
2+
3+
import com.xpeho.spring_boot_java_random_user.domain.exceptions.InvalidPaginationException;
4+
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.bind.annotation.ExceptionHandler;
10+
import org.springframework.web.bind.annotation.RestControllerAdvice;
11+
12+
@RestControllerAdvice
13+
public class GlobalExceptionHandler {
14+
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
15+
16+
@ExceptionHandler(InvalidPaginationException.class)
17+
public ResponseEntity<ErrorResponse> handleInvalidPaginationException(InvalidPaginationException ex) {
18+
logger.warn("Invalid pagination request: {}", ex.getMessage());
19+
return buildErrorResponse("INVALID_PAGINATION", ex.getMessage(), HttpStatus.BAD_REQUEST);
20+
}
21+
22+
@ExceptionHandler(UserNotFoundException.class)
23+
public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException ex) {
24+
logger.warn("User not found: {}", ex.getMessage());
25+
return buildErrorResponse("USER_NOT_FOUND", ex.getMessage(), HttpStatus.NOT_FOUND);
26+
}
27+
28+
@ExceptionHandler(Exception.class)
29+
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
30+
logger.error("Unexpected error occurred", ex);
31+
return buildErrorResponse("INTERNAL_SERVER_ERROR", "An unexpected error occurred", HttpStatus.INTERNAL_SERVER_ERROR);
32+
}
33+
34+
private ResponseEntity<ErrorResponse> buildErrorResponse(String error, String message, HttpStatus status) {
35+
return ResponseEntity.status(status).body(new ErrorResponse(error, message, status.value()));
36+
}
37+
}
38+

0 commit comments

Comments
 (0)