Skip to content

Commit

Permalink
rework forums v4
Browse files Browse the repository at this point in the history
  • Loading branch information
tnaskali committed Sep 3, 2024
1 parent 87ea360 commit 76fc07b
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 41 deletions.
82 changes: 46 additions & 36 deletions src/main/java/li/naska/bgg/repository/BggForumsV4Repository.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package li.naska.bgg.repository;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import li.naska.bgg.repository.model.BggForumsThreadsV4QueryParams;
import li.naska.bgg.repository.model.BggForumsThreadsV4ResponseBody;
import li.naska.bgg.repository.model.BggForumsV4QueryParams;
import li.naska.bgg.repository.model.BggForumsV4ResponseBody;
import li.naska.bgg.exception.UnexpectedServerResponseException;
import li.naska.bgg.repository.model.*;
import li.naska.bgg.util.JsonProcessor;
import li.naska.bgg.util.QueryParameters;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
Expand All @@ -18,38 +16,56 @@
import reactor.core.publisher.Mono;

@Repository
@Slf4j
public class BggForumsV4Repository {

@Autowired
private ObjectMapper objectMapper;
private final JsonProcessor jsonProcessor;

private final WebClient webClient;

public BggForumsV4Repository(
@Autowired WebClient.Builder builder, @Value("${bgg.endpoints.v4.forums}") String endpoint) {
@Autowired WebClient.Builder builder,
@Value("${bgg.endpoints.v4.forums}") String endpoint,
JsonProcessor jsonProcessor) {
this.webClient = builder.baseUrl(endpoint).build();
this.jsonProcessor = jsonProcessor;
}

public Mono<BggForumV4ResponseBody> getForum(Long id) {
return webClient
.get()
.uri(uriBuilder ->
uriBuilder.path("/{id}").queryParam("partial", "essential").build(id))
.accept(MediaType.APPLICATION_JSON)
.acceptCharset(StandardCharsets.UTF_8)
.exchangeToMono(clientResponse -> {
if (clientResponse.statusCode() == HttpStatus.NOT_FOUND) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Forum not found");
} else if (clientResponse.statusCode() != HttpStatus.OK) {
return UnexpectedServerResponseException.from(clientResponse).buildAndThrow();
}
return clientResponse
.bodyToMono(String.class)
.defaultIfEmpty("")
.map(body -> jsonProcessor.toJavaObject(body, BggForumV4ResponseBody.class));
});
}

public Mono<BggForumsV4ResponseBody> getForums(BggForumsV4QueryParams params) {
return webClient
.get()
.uri(uriBuilder ->
uriBuilder.queryParams(QueryParameters.fromPojo(params)).build())
.accept(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_JSON)
.acceptCharset(StandardCharsets.UTF_8)
.retrieve()
.onStatus(
httpStatus -> httpStatus == HttpStatus.BAD_REQUEST,
clientResponse -> Mono.error(
new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown remote error")))
.toEntity(String.class)
.<BggForumsV4ResponseBody>handle((entity, sink) -> {
try {
sink.next(objectMapper.readValue(entity.getBody(), BggForumsV4ResponseBody.class));
} catch (JsonProcessingException e) {
sink.error(
new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()));
.exchangeToMono(clientResponse -> {
if (clientResponse.statusCode() != HttpStatus.OK) {
return UnexpectedServerResponseException.from(clientResponse).buildAndThrow();
}
return clientResponse
.bodyToMono(String.class)
.defaultIfEmpty("")
.map(body -> jsonProcessor.toJavaObject(body, BggForumsV4ResponseBody.class));
});
}

Expand All @@ -60,22 +76,16 @@ public Mono<BggForumsThreadsV4ResponseBody> getThreads(BggForumsThreadsV4QueryPa
.path("/threads")
.queryParams(QueryParameters.fromPojo(params))
.build())
.accept(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_JSON)
.acceptCharset(StandardCharsets.UTF_8)
.retrieve()
.onStatus(
httpStatus -> httpStatus == HttpStatus.BAD_REQUEST,
clientResponse -> Mono.error(
new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown remote error")))
.toEntity(String.class)
.<BggForumsThreadsV4ResponseBody>handle((entity, sink) -> {
try {
sink.next(
objectMapper.readValue(entity.getBody(), BggForumsThreadsV4ResponseBody.class));
} catch (JsonProcessingException e) {
sink.error(
new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()));
.exchangeToMono(clientResponse -> {
if (clientResponse.statusCode() != HttpStatus.OK) {
return UnexpectedServerResponseException.from(clientResponse).buildAndThrow();
}
return clientResponse
.bodyToMono(String.class)
.defaultIfEmpty("")
.map(body -> jsonProcessor.toJavaObject(body, BggForumsThreadsV4ResponseBody.class));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package li.naska.bgg.repository.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import lombok.Data;

@Data
@JsonIgnoreProperties(value = {"hasAngularLink", "descriptors"})
public class BggForumV4ResponseBody {

private String type;
private Long id;
private String name;
private String href;
private String label;
private String labelpl;
private Boolean hasAngularLink;
private List<Breadcrumb> breadcrumbs;
private ImageSets imageSets;

@Data
@JsonIgnoreProperties(value = {"hasAngularLink"})
private static class Breadcrumb {
private String name;
private String href;
}

@Data
public static class ImageSets {

private Image square100;

private Image mediacard100;
}

@Data
public static class Image {

private String src;

@JsonProperty(value = "src@2x")
private String src_at_2x;
}
}
4 changes: 3 additions & 1 deletion src/main/java/li/naska/bgg/resource/v4/FansResource.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package li.naska.bgg.resource.v4;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import li.naska.bgg.repository.BggFansV4Repository;
import li.naska.bgg.repository.model.BggFansV4QueryParams;
Expand Down Expand Up @@ -74,7 +75,8 @@ public Mono<BggFansV4ResponseBody> postFan(@Validated @RequestBody BggFansV4Requ
<i>Example</i> : /fans/{12345}
""",
security = @SecurityRequirement(name = "basicAuth"))
public Mono<BggFansV4ResponseBody> deleteFan(@Validated @PathVariable Integer id) {
public Mono<BggFansV4ResponseBody> deleteFan(
@Validated @PathVariable @Parameter(example = "12345", description = "Fan id.") Integer id) {
return authenticationService
.requiredAuthentication()
.flatMap(authn -> fansRepository.deleteFan(authn.buildBggRequestHeader(), id));
Expand Down
23 changes: 19 additions & 4 deletions src/main/java/li/naska/bgg/resource/v4/ForumsResource.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package li.naska.bgg.resource.v4;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import li.naska.bgg.repository.BggForumsV4Repository;
import li.naska.bgg.repository.model.BggForumsThreadsV4QueryParams;
import li.naska.bgg.repository.model.BggForumsThreadsV4ResponseBody;
import li.naska.bgg.repository.model.BggForumsV4QueryParams;
import li.naska.bgg.repository.model.BggForumsV4ResponseBody;
import li.naska.bgg.repository.model.*;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
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.RestController;
import reactor.core.publisher.Mono;
Expand All @@ -22,6 +21,22 @@ public class ForumsResource {
@Autowired
private BggForumsV4Repository forumsRepository;

@GetMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(
summary = "Get forum",
description =
"""
Get forum by id.
<p>
<i>Syntax</i> : /forums/{id}
<p>
<i>Example</i> : /forums/65
""")
public Mono<BggForumV4ResponseBody> getForum(
@Validated @PathVariable @Parameter(example = "65", description = "Forum id.") Long id) {
return forumsRepository.getForum(id);
}

@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(
summary = "Get forums",
Expand Down

0 comments on commit 76fc07b

Please sign in to comment.