Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] : 대표 코인 정보 조회 API 구현 (GET) #45

Merged
merged 6 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions backend/src/main/java/org/dgu/backend/common/constant/Coin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.dgu.backend.common.constant;

public enum Coin {
BITCOIN("KRW-BTC", "비트코인"),
ETHEREUM("KRW-ETH", "이더리움"),
RIPPLE("KRW-XRP", "리플"),
DOGECOIN("KRW-DOGE", "도지코인"),
WAVE("KRW-WAVES", "웨이브");

private final String marketName;
private final String koreanName;

Coin(String marketName, String koreanName) {
this.marketName = marketName;
this.koreanName = koreanName;
}

public String getMarketName() {
return marketName;
}

public String getKoreanName() {
return koreanName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public enum SuccessStatus implements BaseCode {
SUCCESS_DELETE_PORTFOLIO_SCRAP(HttpStatus.OK, "200", "포트폴리오 즐겨찾기 삭제에 성공했습니다."),
// DashBoard
SUCCESS_GET_USER_BALANCE(HttpStatus.OK, "200", "유저 업비트 잔고 조회에 성공했습니다"),
SUCCESS_GET_USER_COINS(HttpStatus.OK, "200", "유저 보유 코인 조회에 성공했습니다");
SUCCESS_GET_USER_COINS(HttpStatus.OK, "200", "유저 보유 코인 조회에 성공했습니다"),
SUCCESS_GET_REPRESENTATIVE_COINS(HttpStatus.OK, "200", "대표 코인 조회에 성공했습니다");

private final HttpStatus httpStatus;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,12 @@ public ResponseEntity<ApiResponse<List<DashBoardDto.UserCoinResponse>>> getUserC
List<DashBoardDto.UserCoinResponse> userCoins = dashBoardService.getUserCoins(authorizationHeader);
return ApiResponse.onSuccess(SuccessStatus.SUCCESS_GET_USER_COINS, userCoins);
}

// 대표 코인 5개 조회 API
@GetMapping("/coins/representative")
public ResponseEntity<ApiResponse<List<DashBoardDto.RepresentativeCoinResponse>>> getRepresentativeCoins() {

List<DashBoardDto.RepresentativeCoinResponse> representativeCoinResponses = dashBoardService.getRepresentativeCoins();
return ApiResponse.onSuccess(SuccessStatus.SUCCESS_GET_REPRESENTATIVE_COINS, representativeCoinResponses);
}
}
27 changes: 27 additions & 0 deletions backend/src/main/java/org/dgu/backend/dto/DashBoardDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.dgu.backend.util.BigDecimalSerializer;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class DashBoardDto {
@Builder
Expand Down Expand Up @@ -44,4 +45,30 @@ public UserCoin to(User user) {
.build();
}
}
@Builder
@Getter
@AllArgsConstructor
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class RepresentativeCoinResponse {
private String marketName;
private String koreanName;
@JsonSerialize(using = BigDecimalSerializer.class)
private BigDecimal price;
@JsonSerialize(using = BigDecimalSerializer.class)
private BigDecimal changePrice;
@JsonSerialize(using = BigDecimalSerializer.class)
private BigDecimal changeRate;
private Boolean isIncrease;

public static DashBoardDto.RepresentativeCoinResponse of(UpbitDto.Ticker ticker, String koreanName) {
return RepresentativeCoinResponse.builder()
.marketName(ticker.getMarket())
.koreanName(koreanName)
.changePrice(BigDecimal.valueOf(ticker.getPrice()))
.changeRate(BigDecimal.valueOf(ticker.getChangeRate()).setScale(5, RoundingMode.HALF_UP))
.isIncrease(ticker.getChange().equals("RISE"))
.build();
}
}
}
16 changes: 16 additions & 0 deletions backend/src/main/java/org/dgu/backend/dto/UpbitDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,20 @@ public static class Account {
private Double avgBuyPrice;
private String unitCurrency;
}

@Builder
@Getter
@AllArgsConstructor
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Ticker {
private String market;
@JsonProperty("trade_price")
private Double price;
private String change;
@JsonProperty("signed_change_rate")
private Double changeRate;
@JsonProperty("signed_change_price")
private Double changePrice;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
@Getter
@RequiredArgsConstructor
public enum UpbitErrorResult implements BaseErrorCode {
FAIL_ACCESS_USER_ACCOUNT(HttpStatus.NOT_FOUND, "404", "업비트에서 유저 잔고를 가져오는 데 실패했습니다.");
FAIL_ACCESS_USER_ACCOUNT(HttpStatus.NOT_FOUND, "404", "업비트에서 유저 잔고를 가져오는 데 실패했습니다."),
FAIL_ACCESS_COIN_INFO(HttpStatus.NOT_FOUND, "404", "업비트에서 코인 정보를 가져오는 데 실패했습니다.");

private final HttpStatus httpStatus;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
public interface DashBoardService {
DashBoardDto.UserAccountResponse getUserAccount(String authorizationHeader);
List<DashBoardDto.UserCoinResponse> getUserCoins(String authorizationHeader);
List<DashBoardDto.RepresentativeCoinResponse> getRepresentativeCoins();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dgu.backend.common.constant.Coin;
import org.dgu.backend.domain.UpbitKey;
import org.dgu.backend.domain.User;
import org.dgu.backend.domain.UserCoin;
Expand Down Expand Up @@ -40,7 +41,7 @@ public DashBoardDto.UserAccountResponse getUserAccount(String authorizationHeade

String token = jwtUtil.generateUpbitToken(upbitKey.getAccessKey(), upbitKey.getSecretKey());
String url = "https://api.upbit.com/v1/accounts";
UpbitDto.Account[] responseBody = connectUpbitApi(url, token);
UpbitDto.Account[] responseBody = getUserAccountsAtUpbit(url, token);
if (Objects.isNull(responseBody)) {
throw new UpbitException(UpbitErrorResult.FAIL_ACCESS_USER_ACCOUNT);
}
Expand Down Expand Up @@ -69,7 +70,7 @@ public List<DashBoardDto.UserCoinResponse> getUserCoins(String authorizationHead

String token = jwtUtil.generateUpbitToken(upbitKey.getAccessKey(), upbitKey.getSecretKey());
String url = "https://api.upbit.com/v1/accounts";
UpbitDto.Account[] responseBody = connectUpbitApi(url, token);
UpbitDto.Account[] responseBody = getUserAccountsAtUpbit(url, token);
if (Objects.isNull(responseBody)) {
throw new UpbitException(UpbitErrorResult.FAIL_ACCESS_USER_ACCOUNT);
}
Expand Down Expand Up @@ -102,6 +103,22 @@ public List<DashBoardDto.UserCoinResponse> getUserCoins(String authorizationHead
return userCoinResponses;
}

// 대표 코인 5개 정보를 반환하는 메서드
@Override
public List<DashBoardDto.RepresentativeCoinResponse> getRepresentativeCoins() {
String url = "https://api.upbit.com/v1/ticker?markets=";
List<DashBoardDto.RepresentativeCoinResponse> representativeCoinResponses = new ArrayList<>();
for (Coin coin : Coin.values()) {
UpbitDto.Ticker[] responseBody = getTickerPriceAtUpbit(url + coin.getMarketName());
if (Objects.isNull(responseBody[0])) {
throw new UpbitException(UpbitErrorResult.FAIL_ACCESS_COIN_INFO);
}
representativeCoinResponses.add(DashBoardDto.RepresentativeCoinResponse.of(responseBody[0], coin.getKoreanName()));
}

return representativeCoinResponses;
}

// 코인 가격 상승 여부를 판단하는 메서드
private boolean isBalanceIncreased(UpbitDto.Account account, UserCoin userCoin) {
BigDecimal curBalance = BigDecimal.valueOf(account.getBalance())
Expand All @@ -110,8 +127,8 @@ private boolean isBalanceIncreased(UpbitDto.Account account, UserCoin userCoin)
return curBalance.compareTo(userCoin.getBalance()) > 0;
}

// 업비트 API와 통신하는 메서드
private UpbitDto.Account[] connectUpbitApi(String url, String token) {
// 전체 계좌 조회 업비트 API와 통신하는 메서드
private UpbitDto.Account[] getUserAccountsAtUpbit(String url, String token) {
String authenticationToken = "Bearer " + token;
HttpHeaders headers = new HttpHeaders();
headers.set("accept", MediaType.APPLICATION_JSON_VALUE);
Expand All @@ -125,4 +142,18 @@ private UpbitDto.Account[] connectUpbitApi(String url, String token) {

return responseEntity.getBody();
}

// 시세 현재가 조회 업비트 API와 통신하는 메서드
private UpbitDto.Ticker[] getTickerPriceAtUpbit(String url) {
HttpHeaders headers = new HttpHeaders();
headers.set("accept", MediaType.APPLICATION_JSON_VALUE);
ResponseEntity<UpbitDto.Ticker[]> responseEntity = restTemplate.exchange(
url,
HttpMethod.GET,
new HttpEntity<>(headers),
UpbitDto.Ticker[].class
);

return responseEntity.getBody();
}
}
Loading