GoogleBookAdapter added
This commit is contained in:
2
.github/workflows/master.yaml
vendored
2
.github/workflows/master.yaml
vendored
@@ -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
58
pom.xml
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
7
src/component-test/resources/application.yml
Normal file
7
src/component-test/resources/application.yml
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,3 @@ spring:
|
||||
username: sa
|
||||
password: password
|
||||
jpa.database-platform: org.hibernate.dialect.H2Dialect
|
||||
|
||||
ribbon:
|
||||
eureka:
|
||||
enabled: false
|
||||
@@ -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 we’re 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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user