Feign Client 로 HTTP 통신 하기

알파로그·2023년 5월 16일
1

✏️ 필요성

📍 RestTemplate

  • 외부 서버와 통신을 하기위해선 HTTP 메시지를 이용해야 한다.
  • 기존에는 메시지를 작성하고 요청, 응답 받기 위해 RestTemplate 을 사용했었다.
    • ReestTemplate 을 직접 사용할 때 매우 복잡하고,
      응답 받은 값을 직접 하나하나 매핑해줘야 되는 점이 불편했다.

📍 Feign Client 를 적용해 리팩토링

  • Feign 는 HTTP 메시지를 편리하게 통신하기 위한 라이브러리이다.
  • Srping Data JPA 처럼 interface 만으로 구현체 없이 쉽게 HTTP Client 를 구현할 수 있다.

✏️ Feign Client 적용하기

📍 환경설정

  • Dependencies
    - Spring Cloud 는 Spring initializr 에서 Gateway 의 의존성을 추가했을 때 확인할 수 있다.

### Spring Cloud Dependency ###
ext {
	set('springCloudVersion', "2022.0.2")
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

### Feign Dependency ###
dependencies {
	implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' // feign client
}
  • @EnableFeignClients 선언
    • application 을 실행시키는 객체에 선언해줘야 한다.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class BaekerApplication {

	public static void main(String[] args) {
		SpringApplication.run(BaekerApplication.class, args);
	}

}

📍 Feign Client Interface Setting

  • 요청 정보를 설정하는 계층이다.
  • @FeignClient
    • name
      • client 의 이름을 설정할 수 있다.
      • name 은 기능에 영향을 미치지는 않지만 mas 를 운영할 때 유지보수를 위해 어떤 msa 에 요청을 보내는지 식별할 때 사용된다.
    • url
      • 요청을 보낼 url 을 작성한다.
      • Controller 의 @RequestMapping 과 비슷한 기능으로 사용할 수 있다.
  • @Qualifier
    • 동일한 타입의 빈이 여러개 존재할 경우 어떤 빈을 주입할 지 구별해주는 어노테이션이다.
    • 예제에서는 인터페이스 이름인 MemberClient 를 그대로 주입시켜주게 된다.

⚠️ 응답값으로 받을 객체는 기본생정자가 꼭 필요하다.

import com.baeker.baeker.base.request.RsData;
import com.baeker.baeker.feign.dto.MemberJoinDto;
import com.baeker.baeker.msaController.dto.Member;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Map;

@FeignClient(name = "member", url = "http://localhost:8088/member")
@Qualifier
public interface MemberClient {

    @GetMapping("/get_member")
    RsData<Member> findByUsername(@SpringQueryMap Map<String, Object> parm);

    @PostMapping("/create")
    RsData<Member> join(@RequestBody MemberJoinDto dto);
}

📍 Get + param 요청 구현

  • Controller 처럼 원하는 Http method 와 url 을 적어주면 된다.
  • @SpringQueryMap 은 url 에 파라미터를 노출시켜 요청시켜주는 어노테이션이다.
    • 이 때 param key 값과 value 값을 설정하기 위해서 Map 타입을 이용한다.
@GetMapping("/get_member")
RsData<Member> findByUsername(
		@SpringQueryMap Map<String, Object> param
);

📍 Post + message body param 요청 구현

  • 파라미터 정보에 외부에 노출되면 안되는 민감한 정보가 포함되어있을 땐 message body 에 넣어 안전하게 요청해야 한다.
    • @RequestBody 를 선언하면 message body 에 파라미터가 입력된다.
@PostMapping("/create")
RsData<Member> join(
		@RequestBody MemberJoinDto dto
);

📍 PathVariable 요청

  • Controller 를 사용할 때 처럼 그대로 구현해주면 된다.
@GetMapping("/member/{id}"}
RsData<Member> findById(
		@PathVariable(id) Long id
);

✏️ Service 계층

📍 Get + param 요청

  • interface 를 DI 하고, 생성한 method 를 호출하면 HTTP 요청이 완료되고,
    반환값으로 응답값을 얻을 수 있다.
    - 데이터 타입만 일치시켜주면 일일이 JSON Object 로 파싱하지 않아도 자동으로 매핑된다.
    - 이 때 server 에 정의된 반환값과 데이터타입이 일지하지 않을경우 요청이 성공해도 null 값이 반환될 수 있다.

⚠️ client 객체에 정의된 필드값에 server 의 반환값 객체에 정의된 필드값이 없다면 오류가 발생하지 않고 생략된다.

  • 즉, 필요한 필드값만 받아 올 수 있게된다.
...

private final MemberClient client;

...

Map<String, Object> pram = new HashMap<>();
pram.put("username", user.getUsername());

RsData<Member> memberRs = memberClient.findByUsername(pram);

📍 Post + message body param 요청

  • Dto 를 생성해 interface 매서드를 호출하면 완료
...

private final MemberClient client;

...

RsData<Member> memberRs = client.join(new MemberJoinDto(username, nickName, "", provider, email, token, profileImage));
profile
잘못된 내용 PR 환영

0개의 댓글