라우팅

Go Fiber 프레임워크에서 루트의 역할은 서로 다른 URL을 처리 함수에 바인딩하여 HTTP 요청 처리를 지원하는 것입니다. 이는 모든 웹 프레임워크 요청의 진입점으로 작동합니다.

라우트 핸들러 (함수)

특정 HTTP 메서드에 바인딩된 라우트를 등록합니다.

참고: 일부 프레임워크에서는 라우트 핸들러를 컨트롤러라고 부르는데, 이는 일반적으로 들어오는 HTTP 요청을 처리할 함수(메서드)를 결정하는 동일한 의미를 갖습니다.

함수 시그니처:

// HTTP 메서드
func (app *App) Get(path string, handlers ...Handler) Router
func (app *App) Head(path string, handlers ...Handler) Router
func (app *App) Post(path string, handlers ...Handler) Router
func (app *App) Put(path string, handlers ...Handler) Router
func (app *App) Delete(path string, handlers ...Handler) Router
func (app *App) Connect(path string, handlers ...Handler) Router
func (app *App) Options(path string, handlers ...Handler) Router
func (app *App) Trace(path string, handlers ...Handler) Router
func (app *App) Patch(path string, handlers ...Handler) Router

// Add를 사용하여 값을 메서드로 지정할 수 있습니다.
func (app *App) Add(method, path string, handlers ...Handler) Router

// 모든 HTTP 메서드에 라우트를 등록합니다.
// app.Use와 유사하지만 접두어를 바인딩하지 않습니다.
func (app *App) All(path string, handlers ...Handler) Router

예시:

// 간단한 GET 핸들러
app.Get("/api/list", func(c *fiber.Ctx) error {
  return c.SendString("이것은 GET 요청입니다!")
})

// 간단한 POST 핸들러
app.Post("/api/register", func(c *fiber.Ctx) error {
  return c.SendString("이것은 POST 요청입니다!")
})

Use는 미들웨어 및 URL 인터셉터 접두어를 로드하는 데 사용됩니다. 이러한 라우트는 각 경로의 시작 부분과 일치합니다. 예를 들어, /john/john/doe, /johnnnnn 등과 일치합니다.

사용자 정의 미들웨어 함수 시그니처:

func (app *App) Use(args ...interface{}) Router

예시:

// 모든 요청과 일치
app.Use(func(c *fiber.Ctx) error {
    return c.Next()
})

// /api로 시작하는 요청과 일치
app.Use("/api", func(c *fiber.Ctx) error {
    return c.Next()
})

// /api 또는 /home으로 시작하는 요청과 일치 (여러 접두어 지원)
app.Use([]string{"/api", "/home"}, func(c *fiber.Ctx) error {
    return c.Next()
})

// 여러 핸들러 추가
app.Use("/api", func(c *fiber.Ctx) error {
  c.Set("X-Custom-Header", random.String(32))
  return c.Next()
}, func(c *fiber.Ctx) error {
  return c.Next()
})

경로

라우트 경로는 요청 메서드와 함께 엑세스할 수 있는 엔드포인트를 정의합니다. 라우트 경로는 문자열 또는 문자열 패턴일 수 있습니다.

문자열 기반 라우트 경로의 예시

// 이 라우트 경로는 루트 경로인 "/"에 대한 요청과 일치합니다:
app.Get("/", func(c *fiber.Ctx) error {
  return c.SendString("루트 경로")
})

// 이 라우트 경로는 "/about"에 대한 요청과 일치합니다:
app.Get("/about", func(c *fiber.Ctx) error {
  return c.SendString("소개")
})

// 이 라우트 경로는 "/random.txt"에 대한 요청과 일치합니다:
app.Get("/random.txt", func(c *fiber.Ctx) error {
  return c.SendString("랜덤.txt")

expressJs 프레임워크와 유사하게, 라우트를 선언하는 순서가 중요합니다. 요청이 수신되면 라우트는 선언된 순서대로 확인됩니다.

참고: 변수 매개변수를 포함하는 라우트는 잘못된 일치를 방지하기 위해 고정된 부분을 포함하는 라우트 이후에 작성되어야 합니다.

경로 매개변수

경로 매개변수는 경로의 동적인 요소로 이름이 지정된 세그먼트 또는 이름이 지정되지 않은 세그먼트로 나뉠 수 있습니다. 이러한 세그먼트는 URL의 지정된 위치에서 값을 캡처하는 데 사용됩니다. 이러한 값을 검색하려면 Params 함수를 사용하면 되는데, 함수 매개변수는 경로의 루트 매개변수의 이름이며, 이름이 지정되지 않은 매개변수의 경우, 문자(*, +)와 해당 수입니다.

와일드카드 (*) 또는 플러스 기호 (+)는 탐욕스러운 매개변수를 나타냅니다.

경로는 선택적 매개변수를 사용할 수도 있습니다. 이름 있는 매개변수의 경우, 이러한 매개변수는 물음표(?) 뒤에 따르며, 플러스 기호는 선택적이 아니며, 와일드카드 문자는 선택적이고 탐욕스러운 매개변수 범위를 나타내도록 사용할 수 있습니다.

경로 매개변수가 있는 경로 정의의 예

// Parameters
app.Get("/user/:name/books/:title", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s\n", c.Params("name"))
    fmt.Fprintf(c, "%s\n", c.Params("title"))
    return nil
})
// 플러스 - 탐욕스러운 - 선택적이 아님
app.Get("/user/+", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("+"))
})

// 선택적 매개변수
app.Get("/user/:name?", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("name"))
})

// 와일드카드 - 탐욕스러운 - 선택적
app.Get("/user/*", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("*"))
})

// 패러미터 문자가 이스케이핑되어 있기 때문에 이 경로 경로는 "/v1/some/resource/name:customVerb" 요청과 일치할 것입니다
app.Get(`/v1/some/resource/name\:customVerb`, func(c *fiber.Ctx) error {
    return c.SendString("안녕하세요, 커뮤니티")
})

하이픈(-)과 점(.)은 글자 그대로 해석되므로, 유용한 목적으로 경로 매개변수와 함께 사용할 수 있습니다.

모든 특수한 매개변수 문자들은 \를 사용하여 이스케이프할 수 있으며, 이들의 값은 무시될 것입니다. 따라서, 경로에 이를 사용하려면 이스케이프 문자가 정규식 패턴에 영향을 미치지 않도록 항상 모호함이 없도록 `를 사용하는 것이 권장됩니다. 여기에는 Go 정규식 문서에서 항상 이들을 사용하여 패턴을 명확하게 하는 방문을 안내하고 이스케이프 문자가 실수로 패턴에 영향을 줄 수 있음을 방지하기 위한 이유가 있습니다.

// http://localhost:3000/plantae/prunus.persica
app.Get("/plantae/:genus.:species", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s.%s\n", c.Params("genus"), c.Params("species"))
    return nil // prunus.persica
})
// http://localhost:3000/flights/LAX-SFO
app.Get("/flights/:from-:to", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s-%s\n", c.Params("from"), c.Params("to"))
    return nil // LAX-SFO
})

저희의 스마트 라우팅은 소개된 매개변수 문자를 요청 경로의 일부로 인식하고 이를 그에 상응하는 방법으로 처리할 수 있습니다.

// http://localhost:3000/shop/product/color:blue/size:xs
app.Get("/shop/product/color::color/size::size", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s:%s\n", c.Params("color"), c.Params("size"))
    return nil // blue:xs

또한, 라우트는 와일드카드나 플러스 문자와 같은 여러 매개변수와 여러 이름이 지정되지 않은 매개변수 문자를 연속적으로 사용할 수 있으며 이는 경로에서 사용자의 가능성을 크게 확장시키는 가능성을 지닙니다.

// GET /@v1
// Params: "sign" -> "@", "param" -> "v1"
app.Get("/:sign:param", handler)

// GET /api-v1
// Params: "name" -> "v1" 
app.Get("/api-:name", handler)

// GET /customer/v1/cart/proxy
// Params: "*1" -> "customer/", "*2" -> "/cart"
app.Get("/*v1*/proxy", handler)

// GET /v1/brand/4/shop/blue/xs
// Params: "*1" -> "brand/4", "*2" -> "blue/xs"
app.Get("/v1/*/shop/*", handler)

저희는 이미 Express 라우팅에 라우팅을 맞추었지만, 여기에 정규식을 아직 지원하지는 않습니다. 왜냐하면 그것들은 비교적 느리기 때문입니다.

제약 사항

들어오는 URL과 URL 경로가 매칭되고 URL 경로가 매개변수를 통해 route 값으로 나누어질 때, 제약 사항이 실행됩니다. 이 기능은 v2.37.0에서 소개되었으며 .NET Core에서 영감을 받았습니다.

제약 사항은 매개변수 유효성 검사를 위한 것이 아닙니다. 매개변수 값에 대해 제약 사항이 유효하지 않으면 Fiber는 404 핸들러를 반환합니다.

제약 사항 예시 예시 일치
int :id 123456789, -123456789
bool :active true, false
guid :id CD2C1638-1638-72D5-1638-DEADBEEF1638
float :weight 1.234, -1,001.01e8
minLen(value) :username<minLen(4)> test (최소 4자 이상)
maxLen(value) :filename<maxLen(8)> MyFile (최대 8자)
len(length) :filename<len(12)> somefile.txt (12자)
min(value) :age<min(18)> 19 (정수 값은 18 이상이어야 함)
max(value) :age<max(120)> 91 (정수 값은 120을 초과할 수 없음)
range(min,max) :age<range(18,120)> 91 (정수 값은 18 이상이어야 하지만 120을 초과할 수 없음)
alpha :name Rick (문자열은 알파벳 문자 하나 이상이어야 함, 대소문자 구분 없음, a-z)
datetime :dob<datetime(2006\\-01\\-02)> 2005-11-01
regex(expression) :date<regex(\d{4}-\d{2}-\d{2})> 2022-08-27 (정규 표현식과 일치해야 함)

예시

  • 단일 제약 사항
  • 다중 제약 사항
  • 정규 표현식 제약 사항
app.Get("/:test", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("test"))
})

// curl -X GET http://localhost:3000/12 // 12

// curl -X GET http://localhost:3000/1 // GET /1을 찾을 수 없음


여러 제약 사항을 추가하려면 `;`를 사용할 수 있습니다.

app.Get("/:test", func(c *fiber.Ctx) error { return c.SendString(c.Params("test")) })

// curl -X GET http://localhost:3000/120000 // GET /120000을 찾을 수 없음

// curl -X GET http://localhost:3000/1 // GET /1을 찾을 수 없음

// curl -X GET http://localhost:3000/250 // 250


Fiber는 라우트 등록 시 정규 표현식 제약에 대한 성능 오버헤드가 없도록 정규 표현식 쿼리를 사전 컴파일합니다.

```go
app.Get(`/:date`, func(c *fiber.Ctx) error {
  return c.SendString(c.Params("date"))
})

// curl -X GET http://localhost:3000/125 // GET /125을 찾을 수 없음

// curl -X GET http://localhost:3000/test // GET /test을 찾을 수 없음

// curl -X GET http://localhost:3000/2022-08-27 // 2022-08-27


> 날짜-시간 제약 사항(`*`,`+`,`?`,`:`,`/`,``,``>,`;`,`(`,`)`)을 사용할 때는 경로에서 특수 문자를 오해하지 않도록 특수 문자 앞에 `\\`를 사용하세요.

**옵션 매개변수 예시**

옵션 매개변수에도 제약 사항을 추가할 수 있습니다.
```go
app.Get("/:test?", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/42
// 42
// curl -X GET http://localhost:3000/
//
// curl -X GET http://localhost:3000/7.0
// GET /7.0을 찾을 수 없음

미들웨어

사용자 요청 또는 응답을 조작하는 데 사용되는 함수들은 미들웨어 함수라고 합니다. Next는 현재 경로와 일치하는 next 함수를 실행하는 Fiber 라우팅 함수입니다.

미들웨어 함수 예시

app.Use(func(c *fiber.Ctx) error {
  // 모든 응답에 사용자 지정 헤더 설정:
  c.Set("X-Custom-Header", "안녕, 세계")

  // 다음 미들웨어로 진행:
  return c.Next()
})

app.Get("/", func(c *fiber.Ctx) error {
  return c.SendString("안녕, 세계!")
})

Use 메서드의 경로는 마운트 경로 또는 접두사 경로일 수 있으며, 해당 경로로 시작하는 경로의 요청에만 미들웨어를 적용합니다.

런타임에 라우트 제한 추가

설계 및 성능 고려 사항으로 인해 애플리케이션 시작 후에 동적으로 라우트를 추가하는 것은 지원되지 않습니다. 애플리케이션이 시작되기 전에 모든 라우트가 정의되었는지 확인하십시오.

그루핑

여러 엔드포인트가 있는 경우 Group을 사용하여 라우트를 구성할 수 있습니다.

func main() {
  app := fiber.New()

  api := app.Group("/api", middleware) // /api

  v1 := api.Group("/v1", middleware)   // /api/v1
  v1.Get("/list", handler)             // /api/v1/list
  v1.Get("/user", handler)             // /api/v1/user

  v2 := api.Group("/v2", middleware)   // /api/v2
  v2.Get("/list", handler)             // /api/v2/list
  v2.Get("/user", handler)             // /api/v2/user

  log.Fatal(app.Listen(":3000"))
}