From b9dbeb6c58d19e7ca88e56086136678cc2883a66 Mon Sep 17 00:00:00 2001
From: andrebrowne <42154231+andrebrowne@users.noreply.github.com>
Date: Fri, 2 Oct 2020 13:21:18 -0400
Subject: [PATCH] BAEL-4012 Add Netflix Feign (#10110)
* BAEL-4012 Add Netflix Feign
* BAEL-4012 Cleanup pom
---
.../spring-cloud-netflix-feign/pom.xml | 71 +++++++++++++++++++
.../netflix/feign/ExampleApplication.java | 16 +++++
.../feign/client/JSONPlaceHolderClient.java | 25 +++++++
.../feign/config/ClientConfiguration.java | 38 ++++++++++
.../feign/config/CustomErrorDecoder.java | 21 ++++++
.../feign/exception/BadRequestException.java | 21 ++++++
.../feign/exception/NotFoundException.java | 21 ++++++
.../hystrix/JSONPlaceHolderFallback.java | 22 ++++++
.../cloud/netflix/feign/model/Post.java | 41 +++++++++++
.../feign/service/JSONPlaceHolderService.java | 12 ++++
.../impl/JSONPlaceHolderServiceImpl.java | 26 +++++++
.../src/main/resources/application.properties | 3 +
.../netflix/feign/ExampleTestApplication.java | 21 ++++++
.../netflix/feign/NetflixFeignUnitTest.java | 43 +++++++++++
14 files changed, 381 insertions(+)
create mode 100644 spring-cloud/spring-cloud-netflix-feign/pom.xml
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/ExampleApplication.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/ClientConfiguration.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/CustomErrorDecoder.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/BadRequestException.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/NotFoundException.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/hystrix/JSONPlaceHolderFallback.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/model/Post.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/JSONPlaceHolderService.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/impl/JSONPlaceHolderServiceImpl.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/ExampleTestApplication.java
create mode 100644 spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java
diff --git a/spring-cloud/spring-cloud-netflix-feign/pom.xml b/spring-cloud/spring-cloud-netflix-feign/pom.xml
new file mode 100644
index 0000000000..aa5ba5dbdb
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+ com.baeldung.cloud
+ spring-cloud-netlix-feign
+ 0.0.1-SNAPSHOT
+ spring-cloud-netflix-feign
+ Netflix Feign project for Spring Boot
+
+
+ com.baeldung
+ parent-boot-1
+ 0.0.1-SNAPSHOT
+ ../../parent-boot-1
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-feign
+
+
+
+ com.netflix.feign
+ feign-okhttp
+ ${feign-ok.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.apache.httpcomponents
+ httpcore
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ Camden.SR7
+ 8.18.0
+
+
+
+
+
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/ExampleApplication.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/ExampleApplication.java
new file mode 100644
index 0000000000..e5ed9cbecf
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/ExampleApplication.java
@@ -0,0 +1,16 @@
+package com.baeldung.cloud.netflix.feign;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableFeignClients
+public class ExampleApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+
+}
+
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java
new file mode 100644
index 0000000000..80a455a4c4
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java
@@ -0,0 +1,25 @@
+package com.baeldung.cloud.netflix.feign.client;
+
+import com.baeldung.cloud.netflix.feign.config.ClientConfiguration;
+import com.baeldung.cloud.netflix.feign.hystrix.JSONPlaceHolderFallback;
+import com.baeldung.cloud.netflix.feign.model.Post;
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.util.List;
+
+@FeignClient(value = "jplaceholder",
+ url = "https://jsonplaceholder.typicode.com/",
+ configuration = ClientConfiguration.class,
+ fallback = JSONPlaceHolderFallback.class)
+public interface JSONPlaceHolderClient {
+
+ @RequestMapping(method = RequestMethod.GET, value = "/posts")
+ List getPosts();
+
+
+ @RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
+ Post getPostById(@PathVariable("postId") Long postId);
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/ClientConfiguration.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/ClientConfiguration.java
new file mode 100644
index 0000000000..bc211b181e
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/ClientConfiguration.java
@@ -0,0 +1,38 @@
+package com.baeldung.cloud.netflix.feign.config;
+
+import feign.Logger;
+import feign.RequestInterceptor;
+import feign.codec.ErrorDecoder;
+import feign.okhttp.OkHttpClient;
+
+import org.apache.http.entity.ContentType;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ClientConfiguration {
+
+ @Bean
+ public Logger.Level feignLoggerLevel() {
+ return Logger.Level.FULL;
+ }
+
+ @Bean
+ public ErrorDecoder errorDecoder() {
+ return new ErrorDecoder.Default();
+ }
+
+ @Bean
+ public OkHttpClient client() {
+ return new OkHttpClient();
+ }
+
+ @Bean
+ public RequestInterceptor requestInterceptor() {
+ return requestTemplate -> {
+ requestTemplate.header("user", "ajeje");
+ requestTemplate.header("password", "brazof");
+ requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
+ };
+ }
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/CustomErrorDecoder.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/CustomErrorDecoder.java
new file mode 100644
index 0000000000..3e0e80f6d5
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/config/CustomErrorDecoder.java
@@ -0,0 +1,21 @@
+package com.baeldung.cloud.netflix.feign.config;
+
+import com.baeldung.cloud.netflix.feign.exception.BadRequestException;
+import com.baeldung.cloud.netflix.feign.exception.NotFoundException;
+import feign.Response;
+import feign.codec.ErrorDecoder;
+
+public class CustomErrorDecoder implements ErrorDecoder {
+ @Override
+ public Exception decode(String methodKey, Response response) {
+
+ switch (response.status()){
+ case 400:
+ return new BadRequestException();
+ case 404:
+ return new NotFoundException();
+ default:
+ return new Exception("Generic error");
+ }
+ }
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/BadRequestException.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/BadRequestException.java
new file mode 100644
index 0000000000..6a5f60f7c0
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/BadRequestException.java
@@ -0,0 +1,21 @@
+package com.baeldung.cloud.netflix.feign.exception;
+
+public class BadRequestException extends Exception {
+
+ public BadRequestException() {
+ }
+
+ public BadRequestException(String message) {
+ super(message);
+ }
+
+ public BadRequestException(Throwable cause) {
+ super(cause);
+ }
+
+ @Override
+ public String toString() {
+ return "BadRequestException: "+getMessage();
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/NotFoundException.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/NotFoundException.java
new file mode 100644
index 0000000000..a8d89049fd
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/exception/NotFoundException.java
@@ -0,0 +1,21 @@
+package com.baeldung.cloud.netflix.feign.exception;
+
+public class NotFoundException extends Exception {
+
+ public NotFoundException() {
+ }
+
+ public NotFoundException(String message) {
+ super(message);
+ }
+
+ public NotFoundException(Throwable cause) {
+ super(cause);
+ }
+
+ @Override
+ public String toString() {
+ return "NotFoundException: "+getMessage();
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/hystrix/JSONPlaceHolderFallback.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/hystrix/JSONPlaceHolderFallback.java
new file mode 100644
index 0000000000..ab1aa6bf50
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/hystrix/JSONPlaceHolderFallback.java
@@ -0,0 +1,22 @@
+package com.baeldung.cloud.netflix.feign.hystrix;
+
+import com.baeldung.cloud.netflix.feign.client.JSONPlaceHolderClient;
+import com.baeldung.cloud.netflix.feign.model.Post;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.List;
+
+@Component
+public class JSONPlaceHolderFallback implements JSONPlaceHolderClient {
+
+ @Override
+ public List getPosts() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Post getPostById(Long postId) {
+ return null;
+ }
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/model/Post.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/model/Post.java
new file mode 100644
index 0000000000..73dd2bc198
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/model/Post.java
@@ -0,0 +1,41 @@
+package com.baeldung.cloud.netflix.feign.model;
+
+public class Post {
+
+ private String userId;
+ private Long id;
+ private String title;
+ private String body;
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/JSONPlaceHolderService.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/JSONPlaceHolderService.java
new file mode 100644
index 0000000000..d2e174a1f0
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/JSONPlaceHolderService.java
@@ -0,0 +1,12 @@
+package com.baeldung.cloud.netflix.feign.service;
+
+import com.baeldung.cloud.netflix.feign.model.Post;
+
+import java.util.List;
+
+public interface JSONPlaceHolderService {
+
+ List getPosts();
+
+ Post getPostById(Long id);
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/impl/JSONPlaceHolderServiceImpl.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/impl/JSONPlaceHolderServiceImpl.java
new file mode 100644
index 0000000000..0cc8d296f0
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/service/impl/JSONPlaceHolderServiceImpl.java
@@ -0,0 +1,26 @@
+package com.baeldung.cloud.netflix.feign.service.impl;
+
+import com.baeldung.cloud.netflix.feign.client.JSONPlaceHolderClient;
+import com.baeldung.cloud.netflix.feign.model.Post;
+import com.baeldung.cloud.netflix.feign.service.JSONPlaceHolderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class JSONPlaceHolderServiceImpl implements JSONPlaceHolderService {
+
+ @Autowired
+ private JSONPlaceHolderClient jsonPlaceHolderClient;
+
+ @Override
+ public List getPosts() {
+ return jsonPlaceHolderClient.getPosts();
+ }
+
+ @Override
+ public Post getPostById(Long id) {
+ return jsonPlaceHolderClient.getPostById(id);
+ }
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties b/spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties
new file mode 100644
index 0000000000..5927ccb9c1
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.application.name=netflix-feign
+logging.level.com.baeldung.cloud.netflix.feign.client=DEBUG
+feign.hystrix.enabled=true
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/ExampleTestApplication.java b/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/ExampleTestApplication.java
new file mode 100644
index 0000000000..f3c8459f87
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/ExampleTestApplication.java
@@ -0,0 +1,21 @@
+package com.baeldung.cloud.netflix.feign;
+
+import com.baeldung.cloud.netflix.feign.config.ClientConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@EnableAutoConfiguration
+@ContextConfiguration(classes = { ClientConfiguration.class })
+public class ExampleTestApplication {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java b/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java
new file mode 100644
index 0000000000..880948d6d1
--- /dev/null
+++ b/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java
@@ -0,0 +1,43 @@
+package com.baeldung.cloud.netflix.feign;
+
+import com.baeldung.cloud.netflix.feign.model.Post;
+import com.baeldung.cloud.netflix.feign.service.JSONPlaceHolderService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class NetflixFeignUnitTest {
+
+ @Autowired
+ private JSONPlaceHolderService jsonPlaceHolderService;
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+
+ @Test
+ public void whenGetPosts_thenListPostSizeGreaterThanZero() {
+
+ List posts = jsonPlaceHolderService.getPosts();
+
+ assertFalse(posts.isEmpty());
+ }
+
+ @Test
+ public void whenGetPostWithId_thenPostExist() {
+
+ Post post = jsonPlaceHolderService.getPostById(1L);
+
+ assertNotNull(post);
+ }
+
+}