Controller Style Router

Controller API

Basic Usage

  1. import "github.com/beego/beego/v2/server/web"
  2. type UserController struct {
  3. web.Controller
  4. }

Adding methods:

  1. import "github.com/beego/beego/v2/server/web"
  2. type UserController struct {
  3. web.Controller
  4. }
  5. func (u *UserController) HelloWorld() {
  6. u.Ctx.WriteString("hello, world")
  7. }
  8. func main() {
  9. web.AutoRouter(&UserController{})
  10. web.Run()
  11. }

Accessing URL http://127.0.0.1:8080/user/helloworld

hello world.png

Note that the methods inside the controller that handle http requests must be public methods - i.e. initially capitalized and have no parameters and no return value. If your method does not meet this requirement, in most cases, a panic will occur, e.g. if your method has parameters:

  1. func (u *UserController) HelloWorldNoPtr(name string) {
  2. u.Ctx.WriteString("don't work")
  3. }

Note that the HandleFunc in functional style actually takes a *Context parameter

Or:

  1. func (u UserController) HelloWorldNoPtr() {
  2. u.Ctx.WriteString("don't work")
  3. }

The general convention is to use a pointer receiver, but this is not mandatory. For a discussion of receivers, seechoose receiver

Controller Name

In some of the smarter APIs, we use the Controller name as a prefix, namespace, etc.

In general:

  1. type CtrlNameController struct {
  2. }

For example, if we define a UserController, then the name of the Controller is User. If it is case-insensitive, then user is also a legal name.

Then let’s say we define a BuyerRefundController, then BuyerRefund is the name, and when case insensitive, buyerrefund is also the legal name.

AutoRouter

The routing rules resolved by AutoRouter are determined by the value of RouterCaseSensitive, the name of Controller and the method name.

Where UserController it’s name is User and the method name is HelloWorld. Then.

  • If RouterCaseSensitive is true, then AutoRouter registers two routes, /user/helloworld/*, /User/HelloWorld/*.
  • If RouterCaseSensitive is false, then one route will be registered, /user/helloworld/*.

In summary, it is always correct to use all lowercase paths when using AutoRouter.

AutoPrefix

AutoRouter is internally based on the implementation of AutoPrefix, so to speak, the name of the Controller, which is the registered prefix (prefix).

Example:

  1. import (
  2. "github.com/beego/beego/v2/server/web"
  3. )
  4. type UserController struct {
  5. web.Controller
  6. }
  7. func (u *UserController) HelloWorld() {
  8. u.Ctx.WriteString("Hello, world")
  9. }
  10. func main() {
  11. // get http://localhost:8080/api/user/helloworld
  12. // you will see return "Hello, world"
  13. ctrl := &UserController{}
  14. web.AutoPrefix("api", ctrl)
  15. web.Run()
  16. }

Accessinghttp://localhost:8080/api/user/helloworld and then see “Hello, world”。

Similar to AutoRoute:

  • If RouterCaseSensitive is true, then AutoPrefix registers two routes, api/user/helloworld/*, api/User/HelloWorld/*.

  • If RouterCaseSensitive is false, then one route will be registered, api/user/helloworld/*.

Here we can summarize the rules of a general nature: When we use AutoPrefix, the registered route matches the pattern prefix/ctrlName/methodName.

Manual

If we don’t want to use AutoRoute or AutoPrefix to register routes, because both of them depend on the name of the Controller and also on the name of the method. We may expect more flexibility.

In this scenario, we might consider say, using manual registration to register routes one by one.

In v2.0.2 we introduced a completely new way of registration:

  1. import (
  2. "github.com/beego/beego/v2/server/web"
  3. )
  4. type UserController struct {
  5. web.Controller
  6. }
  7. func (u *UserController) GetUserById() {
  8. u.Ctx.WriteString("GetUserById")
  9. }
  10. func (u *UserController) UpdateUser() {
  11. u.Ctx.WriteString("UpdateUser")
  12. }
  13. func (u *UserController) UserHome() {
  14. u.Ctx.WriteString("UserHome")
  15. }
  16. func (u *UserController) DeleteUser() {
  17. u.Ctx.WriteString("DeleteUser")
  18. }
  19. func (u *UserController) HeadUser() {
  20. u.Ctx.WriteString("HeadUser")
  21. }
  22. func (u *UserController) OptionUsers() {
  23. u.Ctx.WriteString("OptionUsers")
  24. }
  25. func (u *UserController) PatchUsers() {
  26. u.Ctx.WriteString("PatchUsers")
  27. }
  28. func (u *UserController) PutUsers() {
  29. u.Ctx.WriteString("PutUsers")
  30. }
  31. func main() {
  32. // get http://localhost:8080/api/user/123
  33. web.CtrlGet("api/user/:id", (*UserController).GetUserById)
  34. // post http://localhost:8080/api/user/update
  35. web.CtrlPost("api/user/update", (*UserController).UpdateUser)
  36. // http://localhost:8080/api/user/home
  37. web.CtrlAny("api/user/home", (*UserController).UserHome)
  38. // delete http://localhost:8080/api/user/delete
  39. web.CtrlDelete("api/user/delete", (*UserController).DeleteUser)
  40. // head http://localhost:8080/api/user/head
  41. web.CtrlHead("api/user/head", (*UserController).HeadUser)
  42. // patch http://localhost:8080/api/user/options
  43. web.CtrlOptions("api/user/options", (*UserController).OptionUsers)
  44. // patch http://localhost:8080/api/user/patch
  45. web.CtrlPatch("api/user/patch", (*UserController).PatchUsers)
  46. // put http://localhost:8080/api/user/put
  47. web.CtrlPut("api/user/put", (*UserController).PutUsers)
  48. web.Run()
  49. }

It is important to note that our new registration method, requires that when we pass in the method, we pass in (*YourController).MethodName. This is because of a Go language feature that requires that if you wish to get the method when the receiver is a pointer, then you should use (*YourController).

Without pointer:

  1. import (
  2. "github.com/beego/beego/v2/server/web"
  3. )
  4. type UserController struct {
  5. web.Controller
  6. }
  7. func (u UserController) GetUserById() {
  8. u.Ctx.WriteString("GetUserById")
  9. }
  10. func (u UserController) UpdateUser() {
  11. u.Ctx.WriteString("UpdateUser")
  12. }
  13. func (u UserController) UserHome() {
  14. u.Ctx.WriteString("UserHome")
  15. }
  16. func (u UserController) DeleteUser() {
  17. u.Ctx.WriteString("DeleteUser")
  18. }
  19. func (u UserController) HeadUser() {
  20. u.Ctx.WriteString("HeadUser")
  21. }
  22. func (u UserController) OptionUsers() {
  23. u.Ctx.WriteString("OptionUsers")
  24. }
  25. func (u UserController) PatchUsers() {
  26. u.Ctx.WriteString("PatchUsers")
  27. }
  28. func (u UserController) PutUsers() {
  29. u.Ctx.WriteString("PutUsers")
  30. }
  31. func main() {
  32. // get http://localhost:8080/api/user/123
  33. web.CtrlGet("api/user/:id", UserController.GetUserById)
  34. // post http://localhost:8080/api/user/update
  35. web.CtrlPost("api/user/update", UserController.UpdateUser)
  36. // http://localhost:8080/api/user/home
  37. web.CtrlAny("api/user/home", UserController.UserHome)
  38. // delete http://localhost:8080/api/user/delete
  39. web.CtrlDelete("api/user/delete", UserController.DeleteUser)
  40. // head http://localhost:8080/api/user/head
  41. web.CtrlHead("api/user/head", UserController.HeadUser)
  42. // patch http://localhost:8080/api/user/options
  43. web.CtrlOptions("api/user/options", UserController.OptionUsers)
  44. // patch http://localhost:8080/api/user/patch
  45. web.CtrlPatch("api/user/patch", UserController.PatchUsers)
  46. // put http://localhost:8080/api/user/put
  47. web.CtrlPut("api/user/put", UserController.PutUsers)
  48. web.Run()
  49. }

We recommend that if you use this family of methods, then you should choose to use a structured receiver so that the code looks much cleaner.

The extra thing to notice is the CtrlAny method, which means that any http method can be handled.

Historical Methods

Historically, we have registered routes in such a way:

  1. func main() {
  2. ctrl := &MainController{}
  3. // we register the path / to &MainController
  4. // if we don't pass methodName as third param
  5. // web will use the default mappingMethods
  6. // GET http://localhost:8080 -> Get()
  7. // POST http://localhost:8080 -> Post()
  8. // ...
  9. web.Router("/", ctrl)
  10. // GET http://localhost:8080/health => ctrl.Health()
  11. web.Router("/health", ctrl, "get:Health")
  12. // POST http://localhost:8080/update => ctrl.Update()
  13. web.Router("/update", ctrl, "post:Update")
  14. // support multiple http methods.
  15. // POST or GET http://localhost:8080/update => ctrl.GetOrPost()
  16. web.Router("/getOrPost", ctrl, "get,post:GetOrPost")
  17. // support any http method
  18. // POST, GET, PUT, DELETE... http://localhost:8080/update => ctrl.Any()
  19. web.Router("/any", ctrl, "*:Any")
  20. web.Run()
  21. }

We no longer recommend using this approach because readability and maintainability are not good. Especially when refactoring for method renaming, it is easy to make mistakes.

Reference

check routes

choose receiver Controller API route rules