diff --git a/build.gradle b/build.gradle index 15f8bc5..4575ac7 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,12 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.projectlombok:lombok:1.18.24' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.24' } tasks.named('test') { diff --git a/src/main/java/com/origin/challenge/ChallengeApplication.java b/src/main/java/com/origin/challenge/ChallengeApplication.java index 2db13ea..03160d3 100644 --- a/src/main/java/com/origin/challenge/ChallengeApplication.java +++ b/src/main/java/com/origin/challenge/ChallengeApplication.java @@ -2,6 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import java.net.http.HttpClient; @SpringBootApplication public class ChallengeApplication { @@ -10,4 +13,8 @@ public static void main(String[] args) { SpringApplication.run(ChallengeApplication.class, args); } + @Bean + public HttpClient httpClient() { + return HttpClient.newHttpClient(); + } } diff --git a/src/main/java/com/origin/challenge/controllers/PokemonController.java b/src/main/java/com/origin/challenge/controllers/PokemonController.java index cf56303..a77f20a 100644 --- a/src/main/java/com/origin/challenge/controllers/PokemonController.java +++ b/src/main/java/com/origin/challenge/controllers/PokemonController.java @@ -1,18 +1,46 @@ package com.origin.challenge.controllers; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.util.Map; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; @RestController @RequestMapping("/pokemon") public class PokemonController { + @Autowired + private HttpClient httpClient; + @GetMapping - public ResponseEntity> root() { - return ResponseEntity.ok(Map.of("message", "Hello World")); + public ResponseEntity listPokemon(@RequestParam(name = "page", defaultValue = "1") int page) + throws Exception { + final int limit = 20; + final int offset = page - 1; + final String url = String.format("https://pokeapi.co/api/v2/pokemon?offset=%d&limit=%d", offset, limit); + + final HttpRequest r = HttpRequest.newBuilder() + .uri(new URI(url)) + .header( + "Authorization", + "eyJhbGciOiJIUzI1NiJ9.eyJSb2xlIjoiQWRtaW4iLCJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkphdmFJblVzZ" + + "SIsImV4cCI6MTY2MjA0MjMzNCwiaWF0IjoxNjYyMDQyMzM0fQ.xi3uKpbHXXxE5iTOkDrkHJfpXQhGQGjLHXwC1SE-kFI" + ) + .GET() + .build(); + final HttpResponse r2 = this.httpClient.send(r, HttpResponse.BodyHandlers.ofString()); + + final ObjectMapper objectMapper = new ObjectMapper(); + final PokemonDTO r3 = objectMapper.readValue(r2.body(), PokemonDTO.class); + + return ResponseEntity.ok(r3); } } diff --git a/src/main/java/com/origin/challenge/controllers/PokemonDTO.java b/src/main/java/com/origin/challenge/controllers/PokemonDTO.java new file mode 100644 index 0000000..6507d29 --- /dev/null +++ b/src/main/java/com/origin/challenge/controllers/PokemonDTO.java @@ -0,0 +1,27 @@ +package com.origin.challenge.controllers; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class PokemonDTO { + @JsonProperty("results") + private List results; + + @Data + @NoArgsConstructor + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Type { + @JsonProperty("name") + private String name; + + @JsonProperty("url") + private String url; + } +} diff --git a/src/test/java/com/origin/challenge/controllers/PokemonControllerIntegrationTest.java b/src/test/java/com/origin/challenge/controllers/PokemonControllerIntegrationTest.java new file mode 100644 index 0000000..70bc157 --- /dev/null +++ b/src/test/java/com/origin/challenge/controllers/PokemonControllerIntegrationTest.java @@ -0,0 +1,74 @@ +package com.origin.challenge.controllers; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public class PokemonControllerIntegrationTest { + @Mock + private HttpClient httpClient; + + @InjectMocks + private PokemonController pokemonController; + + + private static HttpResponse httpResponse; + + + @BeforeEach + public void setup() { + httpResponse = mock(HttpResponse.class); + when(httpResponse.body()).thenReturn("{\"count\":1154,\"next\":\"https://pokeapi.co/api/v2/pokemon?offset=20" + + "&limit=20\",\"previous\":null,\"results\":[{\"name\":\"bulbasaur\",\"url\":\"https://pokeapi.co/api" + + "/v2/pokemon/1/\"}]}" + ); + } + + + @Test + void test1() throws Exception { + when(httpClient.send(any(), any())).thenReturn(httpResponse); + final HttpRequest expected = HttpRequest.newBuilder() + .uri(new URI("https://pokeapi.co/api/v2/pokemon?offset=0&limit=20")) + .header( + "Authorization", + "eyJhbGciOiJIUzI1NiJ9.eyJSb2xlIjoiQWRtaW4iLCJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkphdmFJblVzZ" + + "SIsImV4cCI6MTY2MjA0MjMzNCwiaWF0IjoxNjYyMDQyMzM0fQ.xi3uKpbHXXxE5iTOkDrkHJfpXQhGQGjLHXwC1SE-kFI" + ) + .GET() + .build(); + + pokemonController.listPokemon(1); + verify(httpClient, times(1)).send(expected, HttpResponse.BodyHandlers.ofString()); + } + + @Test + void test2() throws Exception { + when(httpClient.send(any(), any())).thenReturn(httpResponse); + final HttpRequest expected = HttpRequest.newBuilder() + .uri(new URI("https://pokeapi.co/api/v2/pokemon?offset=20&limit=20")) + .header( + "Authorization", + "eyJhbGciOiJIUzI1NiJ9.eyJSb2xlIjoiQWRtaW4iLCJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkphdmFJblVzZ" + + "SIsImV4cCI6MTY2MjA0MjMzNCwiaWF0IjoxNjYyMDQyMzM0fQ.xi3uKpbHXXxE5iTOkDrkHJfpXQhGQGjLHXwC1SE-kFI" + ) + .GET() + .build(); + + pokemonController.listPokemon(2); + verify(httpClient, times(1)).send(expected, HttpResponse.BodyHandlers.ofString()); + } +}