Kubernetes 이야기

Resty ( Http & Rest Client library) 본문

개발/go

Resty ( Http & Rest Client library)

kmaster 2022. 8. 26. 22:44
반응형

Resty는 GET, POST, PUT 등 rest api용 client library이다. 

 

https://github.com/go-resty/resty

 

GitHub - go-resty/resty: Simple HTTP and REST client library for Go

Simple HTTP and REST client library for Go. Contribute to go-resty/resty development by creating an account on GitHub.

github.com

 

주요특징

  • GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS 등
  • 설정 및 요청을 위한 간단하고 연결 가능한 방법
  • Content-Type 자동 감지
  • JSON및 XML콘텐츠 유형에 대한 자동 마샬링 및 비정렬화
  • multipart/form-data를 통해 하나 이상의 파일을 쉽게 업로드
  • 백오프 재시도 메커니즘
  • Request.SetContext지원
  • BasicAuth및 Bearer토큰 의 권한 부여 옵션
  • ContentLength모든 요청 또는 특정 요청에 대한 요청 값 설정
  • 사용자 지정 루트 인증서 및 클라이언트 인증서
  • Timeout, RedirectPolicy, Proxy, TLSClientConfig, Transport등과 같은 클라이언트 설정

설치

# go get github.com/go-resty/resty/v2

예제

 

GET

코드

package main

import (
	"fmt"

	"github.com/go-resty/resty/v2"
)

func main() {
	client := resty.New()

	resp, err := client.R().
		EnableTrace().
		Get("https://httpbin.org/get")

	// Explore response object
	fmt.Println("Response Info:")
	fmt.Println("  Error      :", err)
	fmt.Println("  Status Code:", resp.StatusCode())
	fmt.Println("  Status     :", resp.Status())
	fmt.Println("  Proto      :", resp.Proto())
	fmt.Println("  Time       :", resp.Time())
	fmt.Println("  Received At:", resp.ReceivedAt())
	fmt.Println("  Body       :\n", resp)
	fmt.Println()
    
	// Explore trace info
	fmt.Println("Request Trace Info:")
	ti := resp.Request.TraceInfo()
	fmt.Println("  DNSLookup     :", ti.DNSLookup)
	fmt.Println("  ConnTime      :", ti.ConnTime)
	fmt.Println("  TCPConnTime   :", ti.TCPConnTime)
	fmt.Println("  TLSHandshake  :", ti.TLSHandshake)
	fmt.Println("  ServerTime    :", ti.ServerTime)
	fmt.Println("  ResponseTime  :", ti.ResponseTime)
	fmt.Println("  TotalTime     :", ti.TotalTime)
	fmt.Println("  IsConnReused  :", ti.IsConnReused)
	fmt.Println("  IsConnWasIdle :", ti.IsConnWasIdle)
	fmt.Println("  ConnIdleTime  :", ti.ConnIdleTime)
	fmt.Println("  RequestAttempt:", ti.RequestAttempt)
	fmt.Println("  RemoteAddr    :", ti.RemoteAddr.String())
}

실행결과

Response Info:
  Error      : <nil>
  Status Code: 200
  Status     : 200 OK
  Proto      : HTTP/2.0
  Time       : 883.1928ms
  Received At: 2022-08-26 21:06:36.9002239 +0900 KST m=+0.889728801
  Body       :
 {
  "args": {},
  "headers": {
    "Accept-Encoding": "gzip",
    "Host": "httpbin.org",
    "User-Agent": "go-resty/2.7.0 (https://github.com/go-resty/resty)",
    "X-Amzn-Trace-Id": "Root=1-6308b74b-7a4579a116fd7019086b5558"
  },
  "origin": "175.125.61.28",
  "url": "https://httpbin.org/get"
}

Request Trace Info:
  DNSLookup     : 16.4533ms
  ConnTime      : 645.0306ms
  TCPConnTime   : 191.5479ms
  TLSHandshake  : 437.0294ms
  ServerTime    : 192.9436ms
  ResponseTime  : 0s
  TotalTime     : 837.9742ms
  IsConnReused  : false
  IsConnWasIdle : false
  ConnIdleTime  : 0s
  RequestAttempt: 1
  RemoteAddr    : 54.147.68.244:443

다른예

// Create a Resty Client
client := resty.New()

resp, err := client.R().
      SetQueryParams(map[string]string{
          "page_no": "1",
          "limit": "20",
          "sort":"name",
          "order": "asc",
          "random":strconv.FormatInt(time.Now().Unix(), 10),
      }).
      SetHeader("Accept", "application/json").
      SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
      Get("/search_result")

 

POST

코드

package main

import (
	"fmt"

	"github.com/go-resty/resty/v2"
)

func main() {
	client := resty.New()

	resp, _ := client.R().
		SetHeader("Content-Type", "application/json").
		SetBody(`{"id":"testuser"}`).
		SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
		Post("https://httpbin.org/anything")

	// Explore response object
	fmt.Println(resp)
}

실행결과

{
  "args": {},
  "data": "{\"id\":\"testuser\"}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "application/json",
    "Accept-Encoding": "gzip",
    "Authorization": "Bearer C6A79608-782F-4ED0-A11D-BD82FAD829CD",
    "Content-Length": "17",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "go-resty/2.7.0 (https://github.com/go-resty/resty)",
    "X-Amzn-Trace-Id": "Root=1-6308bbcb-335d694830f4786355ad34ff"
  },
  "json": {
    "id": "testuser"
  },
  "method": "POST",
  "origin": "175.125.61.28",
  "url": "https://httpbin.org/anything"
}

 

PUT

코드

package main

import (
	"fmt"

	"github.com/go-resty/resty/v2"
)

type Article struct {
	Title   string
	Content string
	Author  string
	Tags    []string
}

func main() {
	client := resty.New()

	resp, _ := client.R().
		SetBody(Article{
			Title:   "go-resty",
			Content: "This is my article content, oh ya!",
			Author:  "Jeevanandam M",
			Tags:    []string{"article", "sample", "resty"},
		}).
		SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
		Put("https://httpbin.org/anything")

	// Explore response object
	fmt.Println(resp)
}

실행결과

{
  "args": {},
  "data": "{\"Title\":\"go-resty\",\"Content\":\"This is my article content, oh ya!\",\"Author\":\"Jeevanandam M\",\"Tags\":[\"article\",\"sample\",\"resty\"]}",
  "files": {},
  "form": {},
  "headers": {
    "Accept-Encoding": "gzip",
    "Authorization": "Bearer C6A79608-782F-4ED0-A11D-BD82FAD829CD",
    "Content-Length": "128",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "go-resty/2.7.0 (https://github.com/go-resty/resty)",
    "X-Amzn-Trace-Id": "Root=1-6308bd31-705a3a424220481c5cbc97c9"
  },
  "json": {
    "Author": "Jeevanandam M",
    "Content": "This is my article content, oh ya!",
    "Tags": [
      "article",
      "sample",
      "resty"
    ],
    "Title": "go-resty"
  },
  "method": "PUT",
  "origin": "175.125.61.28",
  "url": "https://httpbin.org/anything"
}

 

파일업로드

코드

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"

	"github.com/go-resty/resty/v2"
)

func main() {
	client := resty.New()

	notesBytes, _ := ioutil.ReadFile("test.txt")

	resp, _ := client.R().
		SetFileReader("notes", "text-file.txt", bytes.NewReader(notesBytes)).
		SetFormData(map[string]string{
			"first_name": "Jeevanandam",
			"last_name":  "M",
		}).
		Post("https://httpbin.org/anything")

	// Explore response object
	fmt.Println(resp)
}

실행결과

{
  "args": {},
  "data": "",
  "files": {
    "notes": "i am a boy"
  },
  "form": {
    "first_name": "Jeevanandam",
    "last_name": "M"
  },
  "headers": {
    "Accept-Encoding": "gzip",
    "Content-Length": "505",
    "Content-Type": "multipart/form-data; boundary=e634764567bca7406bbe218ec81cfae9b0a7acfd9853ebfa29ca1a12350d",
    "Host": "httpbin.org",
    "User-Agent": "go-resty/2.7.0 (https://github.com/go-resty/resty)",
    "X-Amzn-Trace-Id": "Root=1-6308bef2-692af1806196d02a13b9548e"
  },
  "json": null,
  "method": "POST",
  "origin": "175.125.61.28",
  "url": "https://httpbin.org/anything"
}

 

Form 데이터 전송

코드

package main

import (
	"fmt"

	"github.com/go-resty/resty/v2"
)

func main() {
	client := resty.New()

	resp, _ := client.R().
		SetFormData(map[string]string{
			"username": "jeeva",
			"password": "mypass",
		}).
		Post("https://httpbin.org/anything")

	// Explore response object
	fmt.Println(resp)
}

실행결과

{
  "args": {},
  "files": {},
  "form": {
    "password": "mypass",
    "username": "jeeva"
  },
  "headers": {
    "Accept-Encoding": "gzip",
    "Content-Length": "30",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "User-Agent": "go-resty/2.7.0 (https://github.com/go-resty/resty)",
    "X-Amzn-Trace-Id": "Root=1-6308ca51-5fda234d067f408d69888a12"
  },
  "json": null,
  "method": "POST",
  "origin": "175.125.61.28",
  "url": "https://httpbin.org/anything"
}

 

재전송

Resty는 백오프를 사용하여 각 시도 후 재시도 간격을 늘릴 수 있다.

 

코드

package main

import (
	"errors"
	"fmt"
	"time"

	"github.com/go-resty/resty/v2"
)

func main() {
	client := resty.New()

	client.
		// Set retry count to non zero to enable retries
		SetRetryCount(3).
		// You can override initial retry wait time.
		// Default is 100 milliseconds.
		SetRetryWaitTime(5 * time.Second).
		// MaxWaitTime can be overridden as well.
		// Default is 2 seconds.
		SetRetryMaxWaitTime(20 * time.Second).
		// SetRetryAfter sets callback to calculate wait time between retries.
		// Default (nil) implies exponential backoff with jitter
		SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
			return 0, errors.New("quota exceeded")
		})

	resp, _ := client.R().
		Get("https://httpbin.org/get")

	// Explore response object
	fmt.Println(resp)
}

 

요청 및 응답 미들웨어

Resty는 요청 및 응답을 조작할 수 있는 미들웨어 기능을 제공한다.

// Create a Resty Client
client := resty.New()

// Registering Request Middleware
client.OnBeforeRequest(func(c *resty.Client, req *resty.Request) error {
    // Now you have access to Client and current Request object
    // manipulate it as per your need

    return nil  // if its success otherwise return error
  })

// Registering Response Middleware
client.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
    // Now you have access to Client and current Response object
    // manipulate it as per your need

    return nil  // if its success otherwise return error
  })

 

OnError 후크

Resty는 다음과 같은 이유로 호출될 수 있는 OnError 후크를 제공한다.

  • 클라이언트가 연결 시간 초과, TLS 핸드셰이크 실패 등으로 인해 요청을 보내지 못한 경우.
  • 요청이 최대 횟수만큼 재시도되었지만 여전히 실패한 경우
// Create a Resty Client
client := resty.New()

client.OnError(func(req *resty.Request, err error) {
  if v, ok := err.(*resty.ResponseError); ok {
    // v.Response contains the last response from the server
    // v.Err contains the original error
  }
  // Log the error, increment a metric, etc...
})

 

TLS Skip

https 통신 시 x509 오류 발생으로 인해 동작에 오류가 발생하는 경우 ( 인증서 만료나 사설인증서의 경우 ) skip 할 수 있는 옵션을 제공한다.

 

client.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })

 

기타 옵션

// Set client timeout as per your need
client.SetTimeout(1 * time.Minute)

// Enable debug mode
client.SetDebug(true)

// Assign Client TLSClientConfig
// One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial
client.SetTLSClientConfig(&tls.Config{ RootCAs: roots })

// Cookies for all request
client.SetCookie(&http.Cookie{
      Name:"go-resty",
      Value:"This is cookie value",
      Path: "/",
      Domain: "sample.com",
      MaxAge: 36000,
      HttpOnly: true,
      Secure: false,
    })
client.SetCookies(cookies)

// Basic Auth for all request
client.SetBasicAuth("myuser", "mypass")

// Enabling Content length value for all request
client.SetContentLength(true)

// Registering global Error object structure for JSON/XML request
client.SetError(&Error{})    // or resty.SetError(Error{})
반응형

'개발 > go' 카테고리의 다른 글

Go 기본 문법  (0) 2022.09.24
GoDS ( Go Data Structures )  (0) 2022.08.24
Viper  (0) 2022.08.23
cobra library 사용법  (0) 2022.08.22
모둘과 패키지  (0) 2022.08.22
Comments