개요

다른 언어들과 마찬가지 Go에서는 여러가지 웹 프레임워크가 존재한다. Gin, Beego, Fiber 등이 존재한다. 여기선 Fiber에 대해 다뤄보고자 한다.

Fiber

처음 Fiber에 대해 다루게 된 이유는 Web framework들 중에선 가장 로고가 멋있어 보였다. 솔직히 말해서 다른 web framework들의 로고는 별로 정감이 가지 않았다; 그래도 로고로 Web framework로 정하는 것은 좀 아닌것 같아 Fiber에 대해 알아보았다.

Fiber은 섬유라는 뜻을 가지고 있는데 아마 광섬유 위에서 빛을 통한 통신만큼 빠르다라는 걸 나타내고자 했나 싶다. Fiber은 Fasthttp라는 web framework를 활용하여 만들어졌다. Fasthttp는 그 이름답게 다수의 요청을 빠르게 처리하기 위해 만들어 졌다.
Fiber은 Fasthttp만큼 빠르지만 더 쉽게 사용할 수 있도록 돕는다. 소개란에서도 확인할 수 있지만 개발 철학이 Node express만큼 쉽게 사용하면서 좋은 성능을 갖는 것이라는 것을 알 수 있다. Express를 쓰던 사람이라면 쉽게 적응할 수 있다.
또한 Web framework 소개란에서 가장 먼저 눈에 띄는게 벤치마킹인데 fiber와 fasthttp가 상당히 많은 데이터를 빠르게 처리한다는 것을 알 수 있다.
하지만 항상 장점만 있는 것은 아닌데 Fasthttp의 경우 성능 향상을 위해 자체적으로 기능을 구현하기 때문에 net/http과 호환이 되지 않는다는 단점이 있다.

테스트

어떤 프로젝트를 진행하던 테스트 케이스를 작성하는 과정은 항상 필요하다. 이는 Fiber에서도 마찬가지 인데 Fiber에서 test를 위한 기능을 제공하고 있다.
먼저 fiber 라이브러리에서 Test라는 메서드를 제공하는데 이것을 활용하여 특정 http request에 대한 response를 받아볼 수 있다.

func (app *App) Test(req *http.Request, msTimeout ...int) (*http.Response, error)

req로 http.Request를 받고 msTimeout의 경우 요청을 기다릴 시간이다.
http.Request는 http 요청에 대한 정보를 담은 구조체이다.
Request를 만드는 NewRequest는 두가지가 존재하는데 net/httpnet/http/httptest에 각각 존재한다.

net/http/httptest에 존재하는 NewRequest이다.

func NewRequest(method, target string, body io.Reader) *http.Request {
    /* ... */
	req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(method + " " + target + " HTTP/1.0\r\n\r\n")))
	if err != nil {
		panic("invalid NewRequest arguments; " + err.Error())
	}
    /* ... */
	return req
}

net/http에 존재하는 NewRequest이다.

func NewRequest(method, url string, body io.Reader) (*Request, error) {
	return NewRequestWithContext(context.Background(), method, url, body)
}

두 함수는 이름은 같지만 동작은 다르기 때문에 유의해야 한다. net/http/httptest의 NewRequest의 경우 단순한 요청(ex. GET PATH PROTOCOL)에 대한 Request 구조체를 반환하는 반면, net/http의 NewRequest의 경우 연결, 요청, 응답에 대한 컨트롤 정보(Context)도 담아 Request를 반환한다.
일반적으로 테스트하는 경우에는 httptest의 것을 활용하면 되고, Client.Do나 Transport.RoundTrip을 이용할 경우 http의 것을 활용하면 된다.

테스트 코드

package main

import (
	"fmt"
	"net/http/httptest"
	"testing"

	"github.com/gofiber/fiber/v2"
	"github.com/stretchr/testify/assert"
)

func TestMain(t *testing.T) {
	app := fiber.New()
	
	app.Get("/api/v1/aaa", func(c *fiber.Ctx) error {
		return c.SendString(string(responseByte))
	})
	app.Get("/api/v1/bbb", func(c *fiber.Ctx) error {
		return c.SendString(string(responseByte))
	})

	tests := []struct {
		description  string
		method       string
		route        string
		expectedCode int
	}{
		{
			description:  "GET http /api/v1/aaa 200",
			method:       "GET",
			route:        "http://127.0.0.1/api/v1/aaa",
			expectedCode: 200,
		},
		{
			description:  "GET http /api/v1/bbb 200",
			method:       "GET",
			route:        "http://127.0.0.1/api/v1/bbb",
			expectedCode: 200,
		},
	}

	for _, test := range tests {
		req := httptest.NewRequest(test.method, test.route, nil)
		resp, _ := app.Test(req)
		assert.Equalf(t, test.expectedCode, resp.StatusCode, test.description)
	}

}


Reference