Skip to content

Commit

Permalink
feat: 유저 id들로 유저 조회 API 개발 (#15)
Browse files Browse the repository at this point in the history
* feat: 유저 id들로 유저를 조회하는 API를 개발한다

* test: UUID에 해당하는 검증을 제외한다
  • Loading branch information
devxb authored Dec 30, 2023
1 parent f06e137 commit 3374db4
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 8 deletions.
13 changes: 13 additions & 0 deletions src/main/java/net/teumteum/user/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package net.teumteum.user.controller;

import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import net.teumteum.core.error.ErrorResponse;
import net.teumteum.user.domain.response.UserGetResponse;
import net.teumteum.user.domain.response.UsersGetByIdResponse;
import net.teumteum.user.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -25,6 +28,16 @@ public UserGetResponse getUserById(@PathVariable("userId") Long userId) {
return userService.getUserById(userId);
}

@GetMapping
@ResponseStatus(HttpStatus.OK)
public UsersGetByIdResponse getUsersById(@RequestParam("id") String userIds) {
var parsedUserIds = Arrays.stream(userIds.split(","))
.map(Long::valueOf)
.toList();

return userService.getUsersById(parsedUserIds);
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResponse handleIllegalArgumentException(IllegalArgumentException illegalArgumentException) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package net.teumteum.user.domain.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import net.teumteum.user.domain.User;

public record UsersGetByIdResponse(
List<UserGetResponse> users
) {

public static UsersGetByIdResponse of(List<User> users) {
return new UsersGetByIdResponse(users.stream()
.map(UserGetResponse::of)
.toList());
}


public record UserGetResponse(
Long id,
String name,
String birth,
Long characterId,
int mannerTemperature,
String authenticated,
ActivityArea activityArea,
String mbti,
String status,
String goal,
Job job,
List<String> interests
) {

public static UserGetResponse of(User user) {
return new UserGetResponse(
user.getId(),
user.getName(),
user.getBirth(),
user.getCharacterId(),
user.getMannerTemperature(),
user.getOauth().getAuthenticated(),
ActivityArea.of(user),
user.getMbti(),
user.getStatus().name(),
user.getGoal(),
Job.of(user),
user.getInterests()
);
}

public record ActivityArea(
String city,
List<String> streets
) {

public static ActivityArea of(User user) {
return new ActivityArea(
user.getActivityArea().getCity(),
user.getActivityArea().getStreet()
);
}

}

public record Job(
String name,
boolean certificated,
@JsonProperty("class")
String jobClass,
String detailClass
) {

public static Job of(User user) {
return new Job(
user.getJob().getName(),
user.getJob().isCertificated(),
user.getJob().getJobClass(),
user.getJob().getDetailJobClass()
);
}
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/net/teumteum/user/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package net.teumteum.user.service;

import java.util.List;
import lombok.RequiredArgsConstructor;
import net.teumteum.user.domain.User;
import net.teumteum.user.domain.UserRepository;
import net.teumteum.user.domain.response.UserGetResponse;
import net.teumteum.user.domain.response.UsersGetByIdResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

@Service
@RequiredArgsConstructor
Expand All @@ -20,4 +24,16 @@ public UserGetResponse getUserById(Long userId) {
return UserGetResponse.of(existUser);
}

public UsersGetByIdResponse getUsersById(List<Long> userIds) {
var existUsers = userRepository.findAllById(userIds);

assertIsAllUserExist(userIds, existUsers);

return UsersGetByIdResponse.of(existUsers);
}

private void assertIsAllUserExist(List<Long> userIds, List<User> existUsers) {
Assert.isTrue(userIds.size() == existUsers.size(),
() -> "요청한 userId들에 해당하는 User가 모두 존재하지 않습니다.");
}
}
3 changes: 2 additions & 1 deletion src/test/java/net/teumteum/user/domain/UserFixture.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.teumteum.user.domain;

import java.util.List;
import java.util.UUID;
import lombok.Builder;

public class UserFixture {
Expand Down Expand Up @@ -53,7 +54,7 @@ public static class UserBuilder {
@Builder.Default
private int mannerTemperature = 36;
@Builder.Default
private Oauth oauth = new Oauth("[email protected]", "naver");
private Oauth oauth = new Oauth(UUID.randomUUID().toString(), "naver");
@Builder.Default
private ActivityArea activityArea = new ActivityArea("서울", List.of("강남", "홍대"));
@Builder.Default
Expand Down
7 changes: 7 additions & 0 deletions src/test/java/net/teumteum/user/integration/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,11 @@ ResponseSpec getUser(String token, Long userId) {
.exchange();
}

ResponseSpec getUsersById(String token, String userIds) {
return webTestClient.get()
.uri("/users?id=" + userIds)
.header(HttpHeaders.AUTHORIZATION, token)
.exchange();
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.teumteum.user.integration;

import net.teumteum.Application;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
Expand All @@ -16,4 +18,10 @@ abstract class IntegrationTest {
@Autowired
protected Repository repository;

@AfterEach
@BeforeEach
void clearAll() {
repository.clear();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.teumteum.user.integration;

import java.util.concurrent.atomic.AtomicLong;
import lombok.RequiredArgsConstructor;
import net.teumteum.user.domain.User;
import net.teumteum.user.domain.UserFixture;
Expand All @@ -20,5 +21,4 @@ User saveAndGetUser() {
void clear() {
userRepository.deleteAll();
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package net.teumteum.user.integration;

import java.util.List;
import net.teumteum.core.error.ErrorResponse;
import net.teumteum.user.domain.response.UserGetResponse;
import net.teumteum.user.domain.response.UsersGetByIdResponse;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -15,12 +17,6 @@ class UserIntegrationTest extends IntegrationTest {
private static final String VALID_TOKEN = "VALID_TOKEN";
private static final String INVALID_TOKEN = "IN_VALID_TOKEN";

@AfterEach
@BeforeEach
void clearAll() {
repository.clear();
}

@Nested
@DisplayName("유저 조회 API는")
class Find_user_api {
Expand Down Expand Up @@ -58,4 +54,53 @@ void Return_400_bad_request_if_not_exists_user_id_received() {
.expectBody(ErrorResponse.class);
}
}

@Nested
@DisplayName("유저 id들로 유저들을 조회하는 API 는")
class Find_users_by_user_ids_api {

@Test
@DisplayName("존재하는 유저의 id들로만 요청이 들어오면, 유저 정보를 응답한다.")
void Return_user_info_if_exist_user_ids_received() {
// given
var user1 = repository.saveAndGetUser();
var user2 = repository.saveAndGetUser();

var expected = UsersGetByIdResponse.of(List.of(user1, user2));

// when
var result = api.getUsersById(VALID_TOKEN, user1.getId() + "," + user2.getId());

// then
Assertions.assertThat(result.expectStatus().isOk()
.expectBody(UsersGetByIdResponse.class)
.returnResult()
.getResponseBody()
).usingRecursiveComparison().isEqualTo(expected);
}

@Test
@DisplayName("존재하지 않는 유저의 id가 포함되어 있다면, 400 Bad Request 를 응답한다.")
void Return_400_bad_request_if_not_exists_user_id_include() {
// given
var exist = repository.saveAndGetUser();
var notExist = 999L;

// when
var result = api.getUsersById(VALID_TOKEN, exist.getId() + "," + notExist);

// then
result.expectStatus().isBadRequest();
}

@Test
@DisplayName("id가 비어있으면, 400 Bad Request 를 응답한다.")
void Return_400_bad_request_if_empty_user_ids_input() {
// when
var result = api.getUsersById(VALID_TOKEN, "");

// then
result.expectStatus().isBadRequest();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ void Return_optional_user_if_exists_user_id() {
Assertions.assertThat(result)
.isPresent()
.usingRecursiveComparison()
.ignoringFields("value.oauth.oAuthAuthenticateInfo")
.isEqualTo(expect);
}
}
Expand Down

0 comments on commit 3374db4

Please sign in to comment.