GoogleBookAdapter added

This commit is contained in:
Wojtek Krzywiec
2020-05-12 22:09:14 +02:00
parent 5c78e9721e
commit fa3f89bda8
12 changed files with 255 additions and 36 deletions

View File

@@ -33,6 +33,6 @@ jobs:
with:
java-version: 11.0.4
- name: SonarCloud Scan
run: mvn -B clean verify -Psonar -Dsonar.login=${{ secrets.SONAR_TOKEN }}
run: mvn -B clean verify -Psonar,component-test -Dsonar.login=${{ secrets.SONAR_TOKEN }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

58
pom.xml
View File

@@ -119,6 +119,64 @@
</build>
<profiles>
<profile>
<id>component-test</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>add-component-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/component-test/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-component-test-resources</id>
<phase>generate-test-resources</phase>
<goals>
<goal>add-test-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/component-test/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
<execution>
<id>failsafe-component-test</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<skipTests>false</skipTests>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>sonar</id>
<properties>

View File

@@ -0,0 +1,46 @@
package io.wkrzywiec.hexagonal.library.application;
import io.restassured.RestAssured;
import io.restassured.response.ValidatableResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.greaterThan;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AddNewBookTest {
@LocalServerPort
private int port;
private String baseURL;
@BeforeEach
public void init(){
this.baseURL = "http://localhost:" + port;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
}
@Test
@DisplayName("Search for a new book in Google Books")
public void whenSearchForBook_thenGetList(){
//when
ValidatableResponse response = given()
.when()
.param("query", "lean startup")
.get( baseURL + "/google/books")
.prettyPeek()
.then();
//then
response.statusCode(HttpStatus.OK.value())
.contentType("application/json")
.body("items.size()", greaterThan(0));
}
}

View File

@@ -0,0 +1,7 @@
spring:
datasource:
url: jdbc:h2:mem:testdb
driverClassName: org.h2.Driver
username: sa
password: password
jpa.database-platform: org.hibernate.dialect.H2Dialect

View File

@@ -0,0 +1,24 @@
package io.wkrzywiec.hexagonal.library.domain.book.model;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Value;
import java.util.List;
@Value
@Builder
public class BookDetailsDTO {
private String bookExternalId;
private String isbn10;
private String isbn13;
private String title;
private List<String> authors;
private String publisher;
private String publishedDate;
private String description;
private int pages;
@EqualsAndHashCode.Exclude
private String imageLink;
}

View File

@@ -0,0 +1,7 @@
package io.wkrzywiec.hexagonal.library.domain.book.ports.incoming;
import io.wkrzywiec.hexagonal.library.domain.book.model.BookDetailsDTO;
public interface GetBookDetails {
BookDetailsDTO handle(String bookId);
}

View File

@@ -0,0 +1,65 @@
package io.wkrzywiec.hexagonal.library.infrastructure;
import io.restassured.path.json.JsonPath;
import io.wkrzywiec.hexagonal.library.domain.book.model.BookDetailsDTO;
import io.wkrzywiec.hexagonal.library.domain.book.ports.incoming.GetBookDetails;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static io.restassured.RestAssured.given;
public class GoogleBooksAdapter implements GetBookDetails {
@Override
public BookDetailsDTO handle(String googleBookId) {
JsonPath response =
given()
.pathParam("bookId", googleBookId)
.when()
.get("https://www.googleapis.com/books/v1/volumes/{bookId}")
.jsonPath();
return BookDetailsDTO.builder()
.bookExternalId(googleBookId)
.isbn10(extractIsbn(response, "ISBN_10"))
.isbn13(extractIsbn(response, "ISBN_13"))
.title(response.getString("volumeInfo.title"))
.authors(extractAuthors(response))
.publisher(response.getString("volumeInfo.publisher"))
.publishedDate(response.getString("volumeInfo.publishedDate"))
.description(response.getString("volumeInfo.description"))
.pages(response.getInt("volumeInfo.pageCount"))
.imageLink(extractImage(response))
.build();
}
private String extractIsbn(JsonPath response, String isbnType){
return response.getList("volumeInfo.industryIdentifiers")
.stream()
.map(isbnObj -> (Map<String, String>) isbnObj)
.filter(isbnMap -> isbnMap.containsValue(isbnType))
.map(isbnMap -> isbnMap.get("identifier"))
.findFirst()
.orElse("");
}
private List<String> extractAuthors(JsonPath response) {
return response.getList("volumeInfo.authors")
.stream()
.map(authorObj -> (String) authorObj)
.collect(Collectors.toList());
}
private String extractImage(JsonPath response){
Map<String, String> imagesMap = response.getMap("volumeInfo.imageLinks");
if (imagesMap.containsKey("thumbnail")){
return imagesMap.get("thumbnail");
} else {
return (String) new ArrayList<Object>(imagesMap.values()).get(0);
}
}
}

View File

@@ -8,7 +8,7 @@ import static io.restassured.RestAssured.given;
@RequiredArgsConstructor
@Component
public class GoogleBooksClient {
public class GoogleBookSearchClient {
public String searchForBooks(String query){
Response response =
@@ -18,13 +18,4 @@ public class GoogleBooksClient {
.get("https://www.googleapis.com/books/v1/volumes?langRestrict=en&maxResults=40&printType=books");
return response.getBody().asString();
}
public String getBookById(String bookId) {
Response response =
given()
.pathParam("bookId", bookId)
.when()
.get("https://www.googleapis.com/books/v1/volumes/{bookId}");
return response.getBody().asString();
}
}

View File

@@ -8,17 +8,12 @@ import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/google/books")
@RequiredArgsConstructor
public class GoogleBooksController {
public class GoogleBooksSearchController {
private final GoogleBooksClient client;
private final GoogleBookSearchClient client;
@GetMapping("")
public ResponseEntity<String> searchForBooks(@RequestParam String query){
@GetMapping(value = "", produces = "application/json")
ResponseEntity<String> searchForBooks(@RequestParam String query){
return new ResponseEntity<>(client.searchForBooks(query), HttpStatus.OK);
}
@GetMapping("/{bookId}")
public ResponseEntity<String> getBookBId(@PathVariable String bookId){
return new ResponseEntity<>(client.getBookById(bookId), HttpStatus.OK);
}
}

View File

@@ -6,8 +6,4 @@ spring:
driverClassName: org.h2.Driver
username: sa
password: password
jpa.database-platform: org.hibernate.dialect.H2Dialect
ribbon:
eureka:
enabled: false
jpa.database-platform: org.hibernate.dialect.H2Dialect

View File

@@ -0,0 +1,39 @@
package io.wkrzywiec.hexagonal.library.infrastructure;
import io.wkrzywiec.hexagonal.library.domain.book.model.BookDetailsDTO;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class GoogleBooksAdapterTest {
GoogleBooksAdapter adapter = new GoogleBooksAdapter();
@Test
@DisplayName("Get book details from Google Books")
public void givenCorrectBookId_whenGetBookDetails_thenReturnBookDetailsDTO(){
//given
String googleBookId = "dWYyCwAAQBAJ";
//when
BookDetailsDTO bookDetails = adapter.handle(googleBookId);
//then
BookDetailsDTO expectedDetails = BookDetailsDTO.builder()
.bookExternalId(googleBookId)
.isbn10("1473545374")
.isbn13("9781473545373")
.title("Homo Deus")
.authors(Collections.singletonList("Yuval Noah Harari"))
.publisher("Random House")
.publishedDate("2016-09-08")
.description("<p><b>**THE MILLION COPY BESTSELLER**</b><br> <b></b><br><b> <i>Sapiens </i>showed us where we came from. In uncertain times, <i>Homo Deus</i> shows us where were going.</b></p><p> Yuval Noah Harari envisions a near future in which we face a new set of challenges. <i>Homo Deus</i> explores the projects, dreams and nightmares that will shape the twenty-first century and beyond from overcoming death to creating artificial life.</p><p> It asks the fundamental questions: how can we protect this fragile world from our own destructive power? And what does our future hold?<br> <b></b><br><b> '<i>Homo Deus</i> will shock you. It will entertain you. It will make you think in ways you had not thought before Daniel Kahneman, bestselling author of <i>Thinking, Fast and Slow</i></b></p>")
.pages(528)
.build();
assertEquals(expectedDetails, bookDetails);
}
}

View File

@@ -11,10 +11,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
public class GoogleBooksClientTest {
public class GoogleBookSearchClientTest {
@Autowired
private GoogleBooksClient client;
private GoogleBookSearchClient client;
@Test
@DisplayName("Search for a book")
@@ -32,13 +32,4 @@ public class GoogleBooksClientTest {
JsonObject response = JsonParser.parseString(responseString).getAsJsonObject();
assertEquals(0, response.get("totalItems").getAsLong());
}
@Test
@DisplayName("Get book details by id")
public void givenCorrectBookId_whenGetBookById_thenGetBookDetails(){
String responseString = client.getBookById("wrOQLV6xB-wC");
JsonObject response = JsonParser.parseString(responseString).getAsJsonObject();
assertEquals("Harry Potter and the Sorcerer's Stone", response.getAsJsonObject("volumeInfo").getAsJsonPrimitive("title").getAsString());
}
}