μ΄λ² API ν΅μ μ νλ©΄μ Feign μ μ¬μ©ν΄λ΄€λλ°, μ΄λ»κ² μ¬μ©νλμ§ μ μ΄λ³΄κ³ μ ν¨.
Feign μ΄λ?
μ΄λΌκ³ κ°λ¨νκ²λ§,
API ν΅μ μ μ΄μ©ν΄μ κ°λ°ν νμκ° μκ²Όλλ°, API λ₯Ό ν΅νμ¬ κ°λ°ν΄ λ³Έ μ μ΄ μκΈ°μ
κ·Έλμ 무μμ ꡬκΈλ§ μμ
-> httpClient λ₯Ό μ΄μ©ν΄μ ν΅μ νλ κ²μ μκ² λ¨ -> κ΄λ ¨ μ½λλ₯Ό 보면μ λΆμ μμ
-> Spring μμλ restTemplate λ₯Ό μ΄μ©νλ€λ μκΈ°λ₯Ό λ€μ -> restTemplate ꡬκΈλ§ λ° ν
μ€νΈ μ½λ μμ±
-> Feign μ΄λΌλ κ²μ λ€μ -> Feign μ μ©ν΄λ³΄μ
λΌλ νλ¦μΌλ‘ μ§ν. (λ¬΄λ € ν루λ§μ μ§νλ νλ¦..)
ν
μ€νΈ μ½λλ₯Ό μμ±νλ©΄μ wireMock, MockMvc, Mockito λ±λ μ¬μ©νλλ°, μ΄λ μΆνμ λ°λ‘..
1. μμ‘΄μ± μΆκ°
- maven μ μ¬μ©νλ―λ‘ pom.xml μ μμ‘΄μ± μΆκ°
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>10.2.3</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>10.2.3</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>10.2.3</version>
</dependency>
|
2. Feign μΈν°νμ΄μ€ μμ±
FeignClient Annotationμ΄ μμΌλ κΉ readme μ μλ basic λ°©λ²μ μ¬μ©.
1
2
3
4
5
6
7
8
9
10
11
12
|
public interface AAAClient {
@RequestLine("GET /list")
ApiResponse<Data> getList(@QueryMap SearchRequest SearchRequest);
@RequestLine("GET /{boardId}")
ApiResponse<BoardDetail> getDetail(@Param(value = "boardId") long boardId);
@RequestLine("PUT /{boardId}")
@Headers("Content-Type: application/json")
ApiResponse<String> putBoard(@Param("boardId") long boardId, BoardDetail boardDetail);
}
|
- Annotation μ¬μ©μ λν΄
- @RequestLine - requestMapping κ³Ό κ°μ κ°λ
, url μμ λΆμ¬μ£Όλ GET, POST, PUT, DELETE μΌλ‘ Rest μ μ©
- @Param - λκΈΈ νλΌλ―Έν°
- @QueryMap - Paramκ³Ό κ°μΌλ, param μ νλΌλ―Έν°κ° 3κ° μ΄μμ΄ μλλ―λ‘ 3κ°μ΄μμ κ²½μ° QueryMap μ¬μ©
- ex) param -> list?start=1 , QueryMap -> list?start=1&end=2&limit=3
- @Headers - ν΄λλ₯Ό μΆκ°ν΄μ€, μλ΅μΈ‘μμ requestBody λ₯Ό μ¬μ©ν κ²½μ° Content-Type: application/json κ³Ό κ°μ΄ μΆκ°ν΄μ€μΌ ν¨.
- μ΄μΈμλ @Body μ @HeaderMap μ΄ μμ.
3. ClientConfig μμ±
2μμ λ§λ μΈν°νμ΄μ€μ λν΄ config μμ±
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Configuration
public class AAAClientConfig {
@Value("${url}")
private String url;
@Bean
public AAAClient aAAClient() {
return Feign.builder()
.retryer(new Retryer.Default())
.client(new OkHttpClient())
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.logger(new Slf4jLogger(AAAClient.class))
.target(AAAClient.class, url);
}
}
|
- λΉλ ν¨ν΄μ μ¬μ©ν κ²μ μ μ μμ.
- μ΅μν(?) httpClient κ° λ³΄μ.
4. Service μμ±
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Service
public class BoardService {
private final AAAClient aAAClient;
public static final Logger LOGGER = LoggerFactory.getLogger(BoardService.class);
@Autowired
public BoardService(AAAClient aAAClient) {
this.aAAClient = aAAClient;
}
public ApiResponse<Data> getList(SurveySearchRequest vo) {
ApiResponse<Data> response;
try {
response = aAAClient.getList(vo);
} catch (FeignException ex) {
LOGGER.error("FeignException {}", ex);
}
return response;
}
// μλ΅
}
|
5. Test μ½λ μμ±
- API μ μ§μ ν΅μ ν νμλ μμ
- ν΄λΉ μλΉμ€ λ‘μ§μ΄ μ μμ μΌλ‘ μλνλμ§ μ¬λΆλ§ νμΈ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public class ServiceTest {
@Rule
public WireMockRule wireMockRule = new WireMockRule();
@Rule
public MockitoRule rule = MockitoJUnit.rule();
private BoardServiceService service;
@Before
public void setUp() {
AAAClient aAAClient = Feign.builder()
.client(new OkHttpClient())
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.logger(new Slf4jLogger(SurveyClient.class))
.logLevel(Logger.Level.FULL)
.target(AAAClient.class, "http://localhost:8080");
service = new AAASurveyService(aAAClient);
}
@Test
public void λͺ©λ‘_test() {
SearchRequest req = new SearchRequest();
req.setStart(0);
req.setLimit(10);
StubMapping accept = stubFor(
get(urlPathMatching("/list"))
.withQueryParam("start", equalTo(req.getStart().toString()))
.withQueryParam("limit", equalTo(req.getLimit().toString()))
.willReturn(aResponse()
.withStatus(200)
.withHeader("content-type", "application/json")
.withBody("{}")
)
);
ApiResponse<Data> ret = service.getList(req);
assertEquals("200", ret.getCode());
assertEquals("OK", ret.getMessage());
}
// μλ΅
}
|
Feign μ€μ λ° μ μ©μ μ΄λ κ² ν΄μ λ.
μΆν 컨νΈλ‘€λ¬λ₯Ό ν΅ν΄ μ€μ API μ μ°κ²°λλμ§ ν
μ€νΈκ° νμ. (MockMvc μ¬μ©)