티스토리 뷰
build.gradle 파일에 의존성을 넣어준다.
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR9")
}
}
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
implementation("io.github.openfeign:feign-httpclient:11.0")
}
Applicaton.kt 에 @EnableFeignClients 어노테이션을 이용해
Feign 클라이언트 사용을 선언해준다.
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.cloud.openfeign.EnableFeignClients
@EnableFeignClients
@SpringBootApplication
class Application {
}
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
application.yml 파일에 외부 서버와의 통신에 필요한 프로퍼티 내용을 추가한다.
(PDNS 서버와의 통신을 위해 작업 중)
props:
powerdns-service:
url: http://localhost:9191/api/v1
api-key: akh4TGJTTGVwTjS4ZXYy
외부와의 통신을 담당할 클라이언트 인터페이스를 만들어 준다.
import shop.janes.apis.client.pdns.dto.DnsGetResponse
import shop.janes.apis.config.PowerDnsConfig
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
@FeignClient(name = "powerdns-service", url = "\${props.powerdns-service.url}", configuration = [PowerDnsConfig::class])
interface PowerDnsServiceClient {
@RequestMapping(method = [RequestMethod.GET], value = ["/servers/localhost/zones/{zoneId}"])
fun get(@PathVariable(name = "zoneId", required = true) zoneId: String): DnsGetResponse
}
이 때, @FeignClent 어노테이션을 이용해 설정해주는 것이 중요한데, url은 프로퍼티 값을 불러오도록 하고,
config 파일을 통해 통신을 할 때 Hearder에 필요한 구성 요소 및 로그 설정 등을 할 수 있다.
또한, 호출할 외부 REST API의 Request Method와 uri 값을 잘 작성해주어야 하는데,
uri에는 기존 컨트롤러와 동일하게 설정해주면 된다.
uri에 따라 @PathVariable, @RequestBody 등의 어노테이션을 이용할 수 있다.
마지막으로 응답을 받을 때는 응답이 오는 구조와 동일하게
데이터 클래스를 작성하여 Reponse를 매핑해올 수 있다.
(필요한 결과만 매핑도 가능)
먼저, config 파일에는 Hearder에 API 통신을 위한 키 값을 설정해주었고,
Feign 클라이언트의 통신 로그를 자세히 보기 위해 로그 레벨도 설정해주었다.
import feign.Logger
import feign.RequestInterceptor
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class PowerDnsConfig {
@Bean
fun feignLoggerLevel(): Logger.Level? {
return Logger.Level.FULL
}
@Bean
fun requestInterceptor(@Value("\${props.powerdns-service.api-key}") key: String) : RequestInterceptor {
return RequestInterceptor {
it.header("X-API-Key", key)
}
}
}
아래는 응답을 받아올 데이터 모델이다.
data class DnsGetResponse(
val id: String,
val name: String,
val dnssec: Boolean,
val rrsets: List<Record>,
val serial: Long
)
data class Record(
var name: String?,
val type: Type?,
val ttl: Int?,
val records: List<Map<String, Any>>?,
val comments: List<Map<String, Any>>?
) {
enum class Type {
A, AAAA, ALIAS, CAA, CNAME, DNAME, LOC, LUA, MX, NS, PTR, RRSIG, SOA, SPF, SRV, TXT
}
}
여기서 문제가 있는데, 응답에 성공을 했을 땐 제대로 값을 받아오는데,
실패 했을 때는 실패 응답 errorMessage 값만은 못 담아왔다.
(이 문제는 해결되면 다시 포스팅 예정)
이제 외부 통신과 연결을 했으니 컨트롤러와 서비스를 작성한다.
import shop.janes.apis.client.pdns.dto.DnsGetResponse
import shop.janes.apis.web.v1.domain.record.service.RecordService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/records/{domain}", "/v1/records/{domain}")
class RecordController(
private val recordService: RecordService
) {
@GetMapping()
fun listRecords(@PathVariable domain: String): ResponseEntity<DnsGetResponse> {
return ResponseEntity.ok(recordService.listRecords(domain))
}
}
import shop.janes.apis.client.pdns.PowerDnsServiceClient
import shop.janes.apis.client.pdns.dto.DnsGetResponse
import org.springframework.stereotype.Service
@Service
class RecordService(
private val powerDnsServiceClient: PowerDnsServiceClient
) {
fun listRecords(domain: String): DnsGetResponse {
return powerDnsServiceClient.get(domain)
}
}
API를 호출하면 아래와 같이 @FeignClient 를 이용해
연결한 외부 서버의 API 호출 값을 그대로 받아올 수 있다.
{
"id": "janes.shop.",
"name": "janes.shop.",
"dnssec": false,
"rrsets": [
{
"name": "www.janes.shop.",
"type": "CNAME",
"ttl": 60,
"records": [
{
"content": ".",
"disabled": false
}
],
"comments": []
}
],
"serial": 2022010402
}
아래처럼 위에서 config 파일에 설정했던 외부 통신 시 찍힌 로그들을 자세히 볼 수 있다.
2022-01-04 15:48:11.162 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] ---> GET http://localhost:9191/api/v1/servers/localhost/zones/janes.shop HTTP/1.1
2022-01-04 15:48:11.162 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] X-API-Key: akh4TGJTTGVwTjS4ZXYy
2022-01-04 15:48:11.162 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] ---> END HTTP (0-byte body)
2022-01-04 15:48:11.877 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] <--- HTTP/1.1 200 OK (715ms)
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] access-control-allow-origin: *
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] connection: close
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] content-length: 738
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] content-security-policy: default-src 'self'; style-src 'self' 'unsafe-inline'
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] content-type: application/json
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] date: Tue, 04 Jan 2022 06:48:12 GMT
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] server: PowerDNS/4.6.0-alpha1.508.master.g853e27067
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] x-content-type-options: nosniff
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] x-frame-options: deny
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] x-permitted-cross-domain-policies: none
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] x-xss-protection: 1; mode=block
2022-01-04 15:48:11.878 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get]
2022-01-04 15:48:11.881 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] {"account": "", "api_rectify": false, "dnssec": false, "edited_serial": 2022010402, "id": "janes.shop.", "kind": "Native", "last_check": 0, "master_tsig_key_ids": [], "masters": [], "name": "janes.shop.", "notified_serial": 0, "nsec3narrow": false, "nsec3param": "", "rrsets": [{"comments": [], "name": "www.janes.shop.", "records": [{"content": ".", "disabled": false}], "ttl": 60, "type": "CNAME"}], "serial": 2022010402, "slave_tsig_key_ids": [], "soa_edit": "", "soa_edit_api": "DEFAULT", "url": "/api/v1/servers/localhost/zones/janes.shop."}
2022-01-04 15:48:11.881 DEBUG 34604 --- [ XNIO-1 task-1] k.h.a.client.pdns.PowerDnsServiceClient : [PowerDnsServiceClient#get] <--- END HTTP (738-byte body)
(참고 : https://velog.io/@skyepodium/2019-10-06-1410-%EC%9E%91%EC%84%B1%EB%90%A8, https://techblog.woowahan.com/2630/)
'Kotlin & JPA' 카테고리의 다른 글
[Kotlin] Gradle json-simple 라이브러리 사용해서 json 파일 불러오기 (0) | 2022.01.18 |
---|---|
[Kotlin] 한글 퓨니코드(Punycode)로 변환 (0) | 2022.01.18 |
[Kotlin] @FeignClient config 설정 (타임아웃 설정) (0) | 2022.01.13 |
[Kotlin] data class 생성자 (0) | 2022.01.10 |
[Kotlin] Extension Function(확장 함수) 사용법 (0) | 2022.01.04 |