-
Notifications
You must be signed in to change notification settings - Fork 4
SpotifyPlayList-dev-009-be-fix-recommend-api-v3 #211
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
2f8c4da
e56f617
3261391
baa60ed
00e84f6
c417155
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,44 +1,42 @@ | ||||||||
| package com.yen.SpotifyPlayList.controller; | ||||||||
|
|
||||||||
| import com.yen.SpotifyPlayList.model.dto.GetRecommendationsDto; | ||||||||
| import com.yen.SpotifyPlayList.service.RecommendationsService; | ||||||||
| import com.yen.SpotifyPlayList.service.CustomSpotifyRecommendationService; | ||||||||
| import lombok.extern.slf4j.Slf4j; | ||||||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||||||
| import org.springframework.http.HttpStatus; | ||||||||
| import org.springframework.http.ResponseEntity; | ||||||||
| import org.springframework.web.bind.annotation.*; | ||||||||
| import se.michaelthelin.spotify.model_objects.specification.Recommendations; | ||||||||
|
|
||||||||
| @Slf4j | ||||||||
| @RestController | ||||||||
| @RequestMapping("/recommend") | ||||||||
| public class RecommendationsController { | ||||||||
|
|
||||||||
| @Autowired | ||||||||
| private RecommendationsService recommendationsService; | ||||||||
| private CustomSpotifyRecommendationService recommendationsService; | ||||||||
|
|
||||||||
| @PostMapping("/") | ||||||||
| public ResponseEntity getRecommendation(@RequestBody GetRecommendationsDto getRecommendationsDto) { | ||||||||
| public ResponseEntity<?> getRecommendation(@RequestBody GetRecommendationsDto getRecommendationsDto) { | ||||||||
| try { | ||||||||
| log.info("(getRecommendation) getRecommendationsDto = " + getRecommendationsDto.toString()); | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For logging, it's better to use parameterized messages instead of string concatenation. This improves performance because the string is only formatted if the log level is enabled, avoiding unnecessary
Suggested change
|
||||||||
| Recommendations recommendations = recommendationsService.getRecommendation(getRecommendationsDto); | ||||||||
| return ResponseEntity.status(HttpStatus.OK).body(recommendations); | ||||||||
| ResponseEntity<String> recommendations = recommendationsService.getRecommendations(getRecommendationsDto); | ||||||||
| return ResponseEntity.status(recommendations.getStatusCode()).body(recommendations.getBody()); | ||||||||
|
Comment on lines
+24
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The service method
Suggested change
|
||||||||
| } catch (Exception e) { | ||||||||
| log.error("getRecommendation error : " + e); | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When logging exceptions, it's crucial to include the full stack trace. Logging just
Suggested change
|
||||||||
| return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| // TODO: Implement custom recommendation logic for playlist-based recommendations | ||||||||
| @GetMapping("/playlist/{playListId}") | ||||||||
| public ResponseEntity getRecommendationWithPlayList(@PathVariable("playListId") String playListId) { | ||||||||
| public ResponseEntity<?> getRecommendationWithPlayList(@PathVariable("playListId") String playListId) { | ||||||||
| try { | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This log.info("(getRecommendationWithPlayList) playListId = {}", playListId); |
||||||||
| log.info("(getRecommendationWithPlayList) playListId = " + playListId); | ||||||||
| Recommendations recommendations = recommendationsService.getRecommendationWithPlayList(playListId); | ||||||||
| return ResponseEntity.status(HttpStatus.OK).body(recommendations); | ||||||||
| return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).body("Feature not yet implemented with custom service"); | ||||||||
| } catch (Exception e) { | ||||||||
| log.error("getRecommendationWithPlayList error : " + e); | ||||||||
| return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,75 @@ | ||||||
| package com.yen.SpotifyPlayList.service; | ||||||
|
|
||||||
| import com.yen.SpotifyPlayList.model.dto.GetRecommendationsDto; | ||||||
| import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.http.*; | ||||||
| import org.springframework.stereotype.Service; | ||||||
| import org.springframework.web.client.RestTemplate; | ||||||
| import org.springframework.web.util.UriComponentsBuilder; | ||||||
|
|
||||||
| @Service | ||||||
| @Slf4j | ||||||
| public class CustomSpotifyRecommendationService { | ||||||
|
|
||||||
| @Value("${spotify.api.base-url:https://api.spotify.com/v1}") | ||||||
| private String spotifyApiBaseUrl; | ||||||
|
|
||||||
| @Autowired | ||||||
| private AuthService authService; | ||||||
|
|
||||||
| @Autowired | ||||||
| private RestTemplate restTemplate; | ||||||
|
|
||||||
| public ResponseEntity<String> getRecommendations(GetRecommendationsDto request) { | ||||||
| try { | ||||||
| String url = buildRecommendationUrl(request); | ||||||
| HttpHeaders headers = new HttpHeaders(); | ||||||
| headers.setBearerAuth(authService.getAccessToken()); | ||||||
| headers.setContentType(MediaType.APPLICATION_JSON); | ||||||
|
|
||||||
| HttpEntity<?> entity = new HttpEntity<>(headers); | ||||||
|
|
||||||
| log.info("Making recommendation request to URL: {}", url); | ||||||
| ResponseEntity<String> response = restTemplate.exchange( | ||||||
| url, | ||||||
| HttpMethod.GET, | ||||||
| entity, | ||||||
| String.class | ||||||
| ); | ||||||
|
|
||||||
| log.info("Received recommendation response: {}", response.getStatusCode()); | ||||||
| return response; | ||||||
|
|
||||||
| } catch (Exception e) { | ||||||
| log.error("Error getting recommendations: {}", e.getMessage()); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When logging exceptions, it's crucial to include the full stack trace for effective debugging. Logging only the message via
Suggested change
|
||||||
| throw new RuntimeException("Failed to get recommendations", e); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| private String buildRecommendationUrl(GetRecommendationsDto request) { | ||||||
| UriComponentsBuilder builder = UriComponentsBuilder | ||||||
| .fromHttpUrl(spotifyApiBaseUrl + "/recommendations"); | ||||||
|
|
||||||
| // Add seed parameters | ||||||
| if (request.getSeedArtistId() != null) { | ||||||
| builder.queryParam("seed_artists", request.getSeedArtistId()); | ||||||
| } | ||||||
| if (request.getSeedTrack() != null) { | ||||||
| builder.queryParam("seed_tracks", request.getSeedTrack()); | ||||||
| } | ||||||
| if (request.getSeedGenres() != null) { | ||||||
| builder.queryParam("seed_genres", request.getSeedGenres()); | ||||||
| } | ||||||
|
|
||||||
| // Add other parameters | ||||||
| builder.queryParam("limit", request.getAmount()); | ||||||
| builder.queryParam("market", request.getMarket()); | ||||||
| builder.queryParam("min_popularity", request.getMinPopularity()); | ||||||
| builder.queryParam("max_popularity", request.getMaxPopularity()); | ||||||
| builder.queryParam("target_popularity", request.getTargetPopularity()); | ||||||
|
Comment on lines
+188
to
+192
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These query parameters are being added to the URL unconditionally. If properties like You should add these parameters only if they have a non-null value, similar to how you handle the seed parameters. if (request.getAmount() != null) {
builder.queryParam("limit", request.getAmount());
}
if (request.getMarket() != null) {
builder.queryParam("market", request.getMarket());
}
if (request.getMinPopularity() != null) {
builder.queryParam("min_popularity", request.getMinPopularity());
}
if (request.getMaxPopularity() != null) {
builder.queryParam("max_popularity", request.getMaxPopularity());
}
if (request.getTargetPopularity() != null) {
builder.queryParam("target_popularity", request.getTargetPopularity());
} |
||||||
|
|
||||||
| return builder.build().encode().toUriString(); | ||||||
| } | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a
RestTemplatewithnew RestTemplate()is not recommended as it comes with no timeouts configured. This can lead to your application threads being blocked indefinitely if the remote service is unresponsive, potentially causing resource exhaustion.It's a best practice to configure connection and read timeouts. The recommended way to create
RestTemplatebeans in Spring Boot is by usingRestTemplateBuilder, which allows for easy configuration.