group.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
  2. // 🤖 GitHub Repository: https://github.com/gofiber/fiber
  3. // 📌 API Documentation: https://docs.gofiber.io
  4. package fiber
  5. import (
  6. "fmt"
  7. "reflect"
  8. )
  9. // Group represents a collection of routes that share middleware and a common
  10. // path prefix.
  11. type Group struct {
  12. app *App
  13. parentGroup *Group
  14. name string
  15. Prefix string
  16. anyRouteDefined bool
  17. }
  18. // Name Assign name to specific route or group itself.
  19. //
  20. // If this method is used before any route added to group, it'll set group name and OnGroupNameHook will be used.
  21. // Otherwise, it'll set route name and OnName hook will be used.
  22. func (grp *Group) Name(name string) Router {
  23. if grp.anyRouteDefined {
  24. grp.app.Name(name)
  25. return grp
  26. }
  27. grp.app.mutex.Lock()
  28. if grp.parentGroup != nil {
  29. grp.name = grp.parentGroup.name + name
  30. } else {
  31. grp.name = name
  32. }
  33. if err := grp.app.hooks.executeOnGroupNameHooks(*grp); err != nil {
  34. panic(err)
  35. }
  36. grp.app.mutex.Unlock()
  37. return grp
  38. }
  39. // Use registers a middleware route that will match requests
  40. // with the provided prefix (which is optional and defaults to "/").
  41. // Also, you can pass another app instance as a sub-router along a routing path.
  42. // It's very useful to split up a large API as many independent routers and
  43. // compose them as a single service using Use. The fiber's error handler and
  44. // any of the fiber's sub apps are added to the application's error handlers
  45. // to be invoked on errors that happen within the prefix route.
  46. //
  47. // app.Use(func(c fiber.Ctx) error {
  48. // return c.Next()
  49. // })
  50. // app.Use("/api", func(c fiber.Ctx) error {
  51. // return c.Next()
  52. // })
  53. // app.Use("/api", handler, func(c fiber.Ctx) error {
  54. // return c.Next()
  55. // })
  56. // subApp := fiber.New()
  57. // app.Use("/mounted-path", subApp)
  58. //
  59. // This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...
  60. func (grp *Group) Use(args ...any) Router {
  61. var subApp *App
  62. var prefix string
  63. var prefixes []string
  64. var handlers []Handler
  65. for i := range args {
  66. switch arg := args[i].(type) {
  67. case string:
  68. prefix = arg
  69. case *App:
  70. subApp = arg
  71. case []string:
  72. prefixes = arg
  73. default:
  74. handler, ok := toFiberHandler(arg)
  75. if !ok {
  76. panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
  77. }
  78. handlers = append(handlers, handler)
  79. }
  80. }
  81. if len(prefixes) == 0 {
  82. prefixes = append(prefixes, prefix)
  83. }
  84. for _, prefix := range prefixes {
  85. if subApp != nil {
  86. return grp.mount(prefix, subApp)
  87. }
  88. grp.app.register([]string{methodUse}, getGroupPath(grp.Prefix, prefix), grp, handlers...)
  89. }
  90. if !grp.anyRouteDefined {
  91. grp.anyRouteDefined = true
  92. }
  93. return grp
  94. }
  95. // Get registers a route for GET methods that requests a representation
  96. // of the specified resource. Requests using GET should only retrieve data.
  97. func (grp *Group) Get(path string, handler any, handlers ...any) Router {
  98. return grp.Add([]string{MethodGet}, path, handler, handlers...)
  99. }
  100. // Head registers a route for HEAD methods that asks for a response identical
  101. // to that of a GET request, but without the response body.
  102. func (grp *Group) Head(path string, handler any, handlers ...any) Router {
  103. return grp.Add([]string{MethodHead}, path, handler, handlers...)
  104. }
  105. // Post registers a route for POST methods that is used to submit an entity to the
  106. // specified resource, often causing a change in state or side effects on the server.
  107. func (grp *Group) Post(path string, handler any, handlers ...any) Router {
  108. return grp.Add([]string{MethodPost}, path, handler, handlers...)
  109. }
  110. // Put registers a route for PUT methods that replaces all current representations
  111. // of the target resource with the request payload.
  112. func (grp *Group) Put(path string, handler any, handlers ...any) Router {
  113. return grp.Add([]string{MethodPut}, path, handler, handlers...)
  114. }
  115. // Delete registers a route for DELETE methods that deletes the specified resource.
  116. func (grp *Group) Delete(path string, handler any, handlers ...any) Router {
  117. return grp.Add([]string{MethodDelete}, path, handler, handlers...)
  118. }
  119. // Connect registers a route for CONNECT methods that establishes a tunnel to the
  120. // server identified by the target resource.
  121. func (grp *Group) Connect(path string, handler any, handlers ...any) Router {
  122. return grp.Add([]string{MethodConnect}, path, handler, handlers...)
  123. }
  124. // Options registers a route for OPTIONS methods that is used to describe the
  125. // communication options for the target resource.
  126. func (grp *Group) Options(path string, handler any, handlers ...any) Router {
  127. return grp.Add([]string{MethodOptions}, path, handler, handlers...)
  128. }
  129. // Trace registers a route for TRACE methods that performs a message loop-back
  130. // test along the path to the target resource.
  131. func (grp *Group) Trace(path string, handler any, handlers ...any) Router {
  132. return grp.Add([]string{MethodTrace}, path, handler, handlers...)
  133. }
  134. // Patch registers a route for PATCH methods that is used to apply partial
  135. // modifications to a resource.
  136. func (grp *Group) Patch(path string, handler any, handlers ...any) Router {
  137. return grp.Add([]string{MethodPatch}, path, handler, handlers...)
  138. }
  139. // Add allows you to specify multiple HTTP methods to register a route.
  140. // The provided handlers are executed in order, starting with `handler` and then the variadic `handlers`.
  141. func (grp *Group) Add(methods []string, path string, handler any, handlers ...any) Router {
  142. converted := collectHandlers("group", append([]any{handler}, handlers...)...)
  143. grp.app.register(methods, getGroupPath(grp.Prefix, path), grp, converted...)
  144. if !grp.anyRouteDefined {
  145. grp.anyRouteDefined = true
  146. }
  147. return grp
  148. }
  149. // All will register the handler on all HTTP methods
  150. func (grp *Group) All(path string, handler any, handlers ...any) Router {
  151. _ = grp.Add(grp.app.config.RequestMethods, path, handler, handlers...)
  152. return grp
  153. }
  154. // Group is used for Routes with common prefix to define a new sub-router with optional middleware.
  155. //
  156. // api := app.Group("/api")
  157. // api.Get("/users", handler)
  158. func (grp *Group) Group(prefix string, handlers ...any) Router {
  159. prefix = getGroupPath(grp.Prefix, prefix)
  160. if len(handlers) > 0 {
  161. converted := collectHandlers("group", handlers...)
  162. grp.app.register([]string{methodUse}, prefix, grp, converted...)
  163. }
  164. // Create new group
  165. newGrp := &Group{Prefix: prefix, app: grp.app, parentGroup: grp}
  166. if err := grp.app.hooks.executeOnGroupHooks(*newGrp); err != nil {
  167. panic(err)
  168. }
  169. return newGrp
  170. }
  171. // RouteChain creates a Registering instance scoped to the group's prefix,
  172. // allowing chained route declarations for the same path.
  173. func (grp *Group) RouteChain(path string) Register {
  174. // Create new group
  175. register := &Registering{app: grp.app, group: grp, path: getGroupPath(grp.Prefix, path)}
  176. return register
  177. }
  178. // Route is used to define routes with a common prefix inside the supplied
  179. // function. It mirrors the legacy helper and reuses the Group method to create
  180. // a sub-router.
  181. func (grp *Group) Route(prefix string, fn func(router Router), name ...string) Router {
  182. if fn == nil {
  183. panic("route handler 'fn' cannot be nil")
  184. }
  185. // Create new group
  186. group := grp.Group(prefix)
  187. if len(name) > 0 {
  188. group.Name(name[0])
  189. }
  190. // Define routes
  191. fn(group)
  192. return group
  193. }