Add owned-games DTO and full profile support
Build, Test & Push Core Service / quality-check (push) Successful in 10s
Build, Test & Push Core Service / docker (push) Successful in 1m44s

Introduce SteamOwnedGamesResponse and SteamProfileAndGamesResponse DTOs and extend SteamApiService with getOwnedGames(...) and getFullPlayerProfile(...) to fetch and combine player summary and owned games. Update SteamTestController to return the combined profile/games response. Remove redundant Steam service URL entries from application.yml. Add SteamApiServiceTest to cover player summary, owned games (including null fields), and the combined profile flow; service falls back to empty lists on errors.
This commit is contained in:
lobo committed 2026-04-19 15:15:15 +02:00
1 parent 1f980c50af
commit 2e3896b00d
6 files changed
+243 -6

No files matched your search

@@ -1,6 +1,6 @@
package core_service.modules.steam_adapter.api;
import core_service.modules.steam_adapter.api.dto.response.SteamPlayerSummaryResponse;
import core_service.modules.steam_adapter.api.dto.response.SteamProfileAndGamesResponse;
import core_service.modules.steam_adapter.service.SteamApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
@@ -21,10 +21,10 @@ public class SteamTestController {
@GetMapping("/{steamId}")
public ResponseEntity<?> testSteamConnection(@PathVariable String steamId) {
Optional<SteamPlayerSummaryResponse.Player> playerOpt = steamApiService.getPlayerSummary(steamId);
Optional<SteamProfileAndGamesResponse> profileOpt = steamApiService.getFullPlayerProfile(steamId);
if (playerOpt.isPresent()) {
return ResponseEntity.ok(playerOpt.get());
if (profileOpt.isPresent()) {
return ResponseEntity.ok(profileOpt.get());
} else {
return ResponseEntity.notFound().build();
}
@@ -0,0 +1,20 @@
package core_service.modules.steam_adapter.api.dto.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public record SteamOwnedGamesResponse(OwnedGamesResponse response) {
public record OwnedGamesResponse(
@JsonProperty("game_count") int gameCount,
List<Game> games
) {}
public record Game(
Integer appid,
String name,
@JsonProperty("playtime_forever") Integer playtimeForever,
@JsonProperty("img_icon_url") String imgIconUrl,
@JsonProperty("has_community_visible_stats") Boolean hasCommunityVisibleStats
) {}
}
@@ -0,0 +1,9 @@
package core_service.modules.steam_adapter.api.dto.response;
import java.util.List;
public record SteamProfileAndGamesResponse(
SteamPlayerSummaryResponse.Player player,
List<SteamOwnedGamesResponse.Game> games
) {
}
@@ -1,12 +1,16 @@
package core_service.modules.steam_adapter.service;
import core_service.modules.steam_adapter.api.dto.response.SteamOwnedGamesResponse;
import core_service.modules.steam_adapter.api.dto.response.SteamPlayerSummaryResponse;
import core_service.modules.steam_adapter.api.dto.response.SteamProfileAndGamesResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@Slf4j
@@ -19,6 +23,16 @@ public class SteamApiService {
@Value("${app.steam.api-key}")
private String apiKey;
public Optional<SteamProfileAndGamesResponse> getFullPlayerProfile(String steamId) {
var playerOpt = getPlayerSummary(steamId);
if (playerOpt.isEmpty()) {
return Optional.empty();
}
var games = getOwnedGames(steamId);
return Optional.of(new SteamProfileAndGamesResponse(playerOpt.get(), games));
}
public Optional<SteamPlayerSummaryResponse.Player> getPlayerSummary(String steamId) {
try {
log.info("Fetching Steam profile for SteamID: {}", steamId);
@@ -42,4 +56,30 @@ public class SteamApiService {
return Optional.empty();
}
public List<SteamOwnedGamesResponse.Game> getOwnedGames(String steamId) {
try {
log.info("Fetching owned games for SteamID: {}", steamId);
SteamOwnedGamesResponse response = steamRestClient.get()
.uri(uriBuilder -> uriBuilder
.path("/IPlayerService/GetOwnedGames/v0001/")
.queryParam("key", apiKey)
.queryParam("steamid", steamId)
.queryParam("include_appinfo", 1)
.queryParam("include_played_free_games", 1)
.build())
.retrieve()
.body(SteamOwnedGamesResponse.class);
if (response != null && response.response() != null && response.response().games() != null) {
return response.response().games();
}
} catch (Exception e) {
log.error("Error communicating with Steam API for games of SteamID: {}", steamId, e);
}
return Collections.emptyList();
}
}
-2
View File
@@ -43,6 +43,4 @@ app:
steam:
api-key: ${STEAM_API_KEY}
base-url: https://api.steampowered.com
playerService-url: https://api.steampowered.com/IPlayerService/GetOwnedGames/v1/
storeService-url: https://api.steampowered.com/IStoreService/GetAppList/v1/
imageService-url: https://cdn.cloudflare.steamstatic.com/steam/apps/
@@ -0,0 +1,170 @@
package core_service.modules.steam_adapter.service;
import core_service.modules.steam_adapter.api.dto.response.SteamOwnedGamesResponse;
import core_service.modules.steam_adapter.api.dto.response.SteamPlayerSummaryResponse;
import core_service.modules.steam_adapter.api.dto.response.SteamProfileAndGamesResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestClient;
import java.util.List;
import java.util.Optional;
import static org.hamcrest.CoreMatchers.containsString;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.queryParam;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
class SteamApiServiceTest {
private SteamApiService steamApiService;
private MockRestServiceServer server;
@BeforeEach
void setUp() {
RestClient.Builder builder = RestClient.builder();
server = MockRestServiceServer.bindTo(builder).build();
steamApiService = new SteamApiService(builder.build());
ReflectionTestUtils.setField(steamApiService, "apiKey", "test-api-key");
}
@Test
void getPlayerSummary_shouldReturnPlayer() {
String steamId = "76561197960435530";
String jsonResponse = """
{
"response": {
"players": [
{
"steamid": "76561197960435530",
"personaname": "TestUser",
"profileurl": "http://steamcommunity.com/id/testuser/",
"avatarfull": "http://media.steampowered.com/avatar.jpg"
}
]
}
}
""";
server.expect(requestTo(containsString("/ISteamUser/GetPlayerSummaries/v0002/")))
.andExpect(queryParam("steamids", steamId))
.andExpect(queryParam("key", "test-api-key"))
.andRespond(withSuccess(jsonResponse, MediaType.APPLICATION_JSON));
Optional<SteamPlayerSummaryResponse.Player> result = steamApiService.getPlayerSummary(steamId);
assertThat(result).isPresent();
assertThat(result.get().personaname()).isEqualTo("TestUser");
}
@Test
void getOwnedGames_shouldReturnGames() {
String steamId = "76561197960435530";
String jsonResponse = """
{
"response": {
"game_count": 1,
"games": [
{
"appid": 10,
"name": "Counter-Strike",
"playtime_forever": 32,
"img_icon_url": "icon_url",
"has_community_visible_stats": true
}
]
}
}
""";
server.expect(requestTo(containsString("/IPlayerService/GetOwnedGames/v0001/")))
.andExpect(queryParam("steamid", steamId))
.andExpect(queryParam("key", "test-api-key"))
.andRespond(withSuccess(jsonResponse, MediaType.APPLICATION_JSON));
List<SteamOwnedGamesResponse.Game> result = steamApiService.getOwnedGames(steamId);
assertThat(result).hasSize(1);
assertThat(result.get(0).name()).isEqualTo("Counter-Strike");
}
@Test
void getOwnedGames_shouldReturnGamesEvenWithNullValues() {
String steamId = "76561197960435530";
String jsonResponse = """
{
"response": {
"game_count": 1,
"games": [
{
"appid": 10,
"name": "Counter-Strike"
}
]
}
}
""";
server.expect(requestTo(containsString("/IPlayerService/GetOwnedGames/v0001/")))
.andRespond(withSuccess(jsonResponse, MediaType.APPLICATION_JSON));
List<SteamOwnedGamesResponse.Game> result = steamApiService.getOwnedGames(steamId);
assertThat(result).hasSize(1);
assertThat(result.get(0).name()).isEqualTo("Counter-Strike");
assertThat(result.get(0).playtimeForever()).isNull();
assertThat(result.get(0).hasCommunityVisibleStats()).isNull();
}
@Test
void getFullPlayerProfile_shouldReturnCombinedResult() {
String steamId = "76561197960435530";
String summaryJson = """
{
"response": {
"players": [
{
"steamid": "76561197960435530",
"personaname": "TestUser",
"profileurl": "url",
"avatarfull": "avatar"
}
]
}
}
""";
String gamesJson = """
{
"response": {
"game_count": 1,
"games": [
{
"appid": 10,
"name": "Counter-Strike",
"playtime_forever": 32,
"img_icon_url": "icon_url",
"has_community_visible_stats": true
}
]
}
}
""";
server.expect(requestTo(containsString("/ISteamUser/GetPlayerSummaries/v0002/")))
.andRespond(withSuccess(summaryJson, MediaType.APPLICATION_JSON));
server.expect(requestTo(containsString("/IPlayerService/GetOwnedGames/v0001/")))
.andRespond(withSuccess(gamesJson, MediaType.APPLICATION_JSON));
Optional<SteamProfileAndGamesResponse> result = steamApiService.getFullPlayerProfile(steamId);
assertThat(result).isPresent();
assertThat(result.get().player().personaname()).isEqualTo("TestUser");
assertThat(result.get().games()).hasSize(1);
assertThat(result.get().games().get(0).name()).isEqualTo("Counter-Strike");
}
}