Skip to main content
Version: 2.8.x(Latest)

Object Registering uses an instantiated object to execute route registration, with every request handled by this object (same object), which remains in memory without being released.

Related Methods:

func (s *Server) BindObject(pattern string, object interface{}, methods ...string) error
func (s *Server) BindObjectMethod(pattern string, object interface{}, method string) error
func (s *Server) BindObjectRest(pattern string, object interface{}) error

Preliminary Convention: The methods that need to be registered for routes must be public methods and the method definition must be:

func(r *ghttp.Request)

Otherwise, registration cannot be completed, and there will be an error prompt during route registration, such as:

panic: API conversion: interface {} is xxx, not func(*ghttp.Request)

Object Registering - BindObject

We can complete object registration using the BindObject method.

package main

import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)

type Controller struct{}

func (c *Controller) Index(r *ghttp.Request) {
r.Response.Write("index")
}

func (c *Controller) Show(r *ghttp.Request) {
r.Response.Write("show")
}

func main() {
s := g.Server()
c := new(Controller)
s.BindObject("/object", c)
s.SetPort(8199)
s.Run()
}

As shown, an object is generated during route registration (the object is generated when the Server is started), and no matter how many requests come in afterward, the Server will delegate the request to the corresponding method of the object for processing. After executing this example, the output route table in the terminal is as follows:

SERVER | DOMAIN  | ADDRESS | METHOD |     ROUTE     |         HANDLER          | MIDDLEWARE
|---------|---------|---------|--------|---------------|--------------------------|------------|
default | default | :8199 | ALL | /object | main.(*Controller).Index |
|---------|---------|---------|--------|---------------|--------------------------|------------|
default | default | :8199 | ALL | /object/index | main.(*Controller).Index |
|---------|---------|---------|--------|---------------|--------------------------|------------|
default | default | :8199 | ALL | /object/show | main.(*Controller).Show |
|---------|---------|---------|--------|---------------|--------------------------|------------|

You can then view the effect via http://127.0.0.1:8199/object/show.

tip

The Index method in the controller is a special method; for example, when the registered route rule is /user, an HTTP request to /user will automatically map to the controller's Index method. That is, accessing /user and /user/index will have the same execution effect.

Built-In Route Variables

When using the BindObject method for object registration, two built-in variables can be used in the route rule: {.struct} and {.method}. The former represents the current object name, and the latter the current registered method name. Let's take a look at an example:

package main

import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)

type Order struct{}

func (o *Order) List(r *ghttp.Request) {
r.Response.Write("list")
}

func main() {
s := g.Server()
o := new(Order)
s.BindObject("/{.struct}-{.method}", o)
s.SetPort(8199)
s.Run()
}

After execution, the terminal outputs the route table as follows:

SERVER | DOMAIN  | ADDRESS | METHOD |    ROUTE    |      HANDLER       | MIDDLEWARE
|---------|---------|---------|--------|-------------|--------------------|------------|
default | default | :8199 | ALL | /order-list | main.(*Order).List |
|---------|---------|---------|--------|-------------|--------------------|------------|

We can try accessing http://127.0.0.1:8199/order-list, and the page will output list. If you don’t use built-in variables in the route rule, then by default, the method will be appended to the end of the specified route rule.

Naming Conventions

When registering routes through objects, route rules can be automatically generated according to the object and method names. The default route rule is that when a method name contains multiple words (words are distinguished by capitalized characters), the route controller automatically uses the hyphen - to connect them, so the method name needs to have a - when accessing.

For example, if the method name is UserName, the generated route will be user-name; if the method name is ShowListItems, the generated route will be show-list-items, and so on.

Additionally, we can use the .Server.SetNameToUriType method to set how route names are generated from object method names. Currently, there are 4 types supported, corresponding to 4 constant definitions:

UriTypeDefault  = 0 // (default) all lowercase, words connected by '-'
UriTypeFullName = 1 // no processing, use the original name to build the URI
UriTypeAllLower = 2 // lowercase only, no connecting symbols between words
UriTypeCamel = 3 // camel case naming

Note: Set this parameter before registering routes through the object, as it will not be effective after the registration. The default rule will be used.

Let's look at an example:

package main

import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)

type User struct{}

func (u *User) ShowList(r *ghttp.Request) {
r.Response.Write("list")
}

func main() {
u := new(User)
s1 := g.Server("UriTypeDefault")
s2 := g.Server("UriTypeFullName")
s3 := g.Server("UriTypeAllLower")
s4 := g.Server("UriTypeCamel")

s1.SetNameToUriType(ghttp.UriTypeDefault)
s2.SetNameToUriType(ghttp.UriTypeFullName)
s3.SetNameToUriType(ghttp.UriTypeAllLower)
s4.SetNameToUriType(ghttp.UriTypeCamel)

s1.BindObject("/{.struct}/{.method}", u)
s2.BindObject("/{.struct}/{.method}", u)
s3.BindObject("/{.struct}/{.method}", u)
s4.BindObject("/{.struct}/{.method}", u)

s1.SetPort(8100)
s2.SetPort(8200)
s3.SetPort(8300)
s4.SetPort(8400)

s1.Start()
s2.Start()
s3.Start()
s4.Start()

g.Wait()
}

To demonstrate the effect contrast, this example uses a multi-Server run method, configuring and running different name conversion methods with different Servers, allowing us to conveniently access different Servers (bound to different ports) in the same program to see different results.

After execution, the terminal outputs the route table as follows:

      SERVER    | DOMAIN  | ADDRESS | METHOD |      ROUTE      |        HANDLER        | MIDDLEWARE
-----------------|---------|---------|--------|-----------------|-----------------------|-------------
UriTypeDefault | default | :8100 | ALL | /user/show-list | main.(*User).ShowList |
-----------------|---------|---------|--------|-----------------|-----------------------|-------------

SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
------------------|---------|---------|--------|----------------|-----------------------|-------------
UriTypeFullName | default | :8200 | ALL | /User/ShowList | main.(*User).ShowList |
------------------|---------|---------|--------|----------------|-----------------------|-------------

SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
------------------|---------|---------|--------|----------------|-----------------------|-------------
UriTypeAllLower | default | :8300 | ALL | /user/showlist | main.(*User).ShowList |
------------------|---------|---------|--------|----------------|-----------------------|-------------

SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
---------------|---------|---------|--------|----------------|-----------------------|-------------
UriTypeCamel | default | :8400 | ALL | /user/showList | main.(*User).ShowList |
---------------|---------|---------|--------|----------------|-----------------------|-------------

You can visit the following URLs to get the desired results:

http://127.0.0.1:8100/user/show-list
http://127.0.0.1:8200/User/ShowList
http://127.0.0.1:8300/user/showlist
http://127.0.0.1:8400/user/showList

Object Method Registration

If there are several public methods in the controller, but you only want to register a few of them and not make others public, what should you do? We can replace the implementation by passing the third optional parameter to BindObject, which supports passing multiple method names separated by a comma , ( method names are case-sensitive).

Example usage:

package main

import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)

type Controller struct{}

func (c *Controller) Index(r *ghttp.Request) {
r.Response.Write("index")
}

func (c *Controller) Show(r *ghttp.Request) {
r.Response.Write("show")
}

func main() {
s := g.Server()
c := new(Controller)
s.BindObject("/object", c, "Show")
s.SetPort(8199)
s.Run()
}

After execution, the terminal outputs the route table as:

SERVER | DOMAIN  | ADDRESS | METHOD |    ROUTE     |         HANDLER         | MIDDLEWARE
|---------|---------|---------|--------|--------------|-------------------------|------------|
default | default | :8199 | ALL | /object/show | main.(*Controller).Show |
|---------|---------|---------|--------|--------------|-------------------------|------------|

Binding Route Methods - BindObjectMethod

We can bind specified routes to specific methods ( method names are case-sensitive ) using the BindObjectMethod.

tip

The difference between BindObjectMethod and BindObject is that BindObjectMethod binds a specific method of the object to the specified route rule, with the third method parameter able to specify only one method name. In contrast, when registering with BindObject, all routes are generated according to rules based on object method names, and the third methods parameter can specify multiple method names for registration.

Here's an example:

package main

import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)

type Controller struct{}

func (c *Controller) Index(r *ghttp.Request) {
r.Response.Write("index")
}

func (c *Controller) Show(r *ghttp.Request) {
r.Response.Write("show")
}

func main() {
s := g.Server()
c := new(Controller)
s.BindObjectMethod("/show", c, "Show")
s.SetPort(8199)
s.Run()
}

After execution, the terminal outputs the route table as follows:

SERVER | DOMAIN  | ADDRESS | METHOD | ROUTE |         HANDLER         | MIDDLEWARE
|---------|---------|---------|--------|-------|-------------------------|------------|
default | default | :8199 | ALL | /show | main.(*Controller).Show |
|---------|---------|---------|--------|-------|-------------------------|------------|

RESTful Object Registering - BindObjectRest

Controllers designed with the RESTful approach are typically used for API services. In this mode, the HTTP Method maps to the corresponding method name in the controller, for instance, the POST method will map to the Post method in the controller (public method, starting with an uppercase letter), and the DELETE method will map to the Delete method in the controller, and so on. Other methods not named using HTTP Method conventions, even if defined as public methods, will not be automatically registered and will be invisible to the application. Of course, if the controller does not define a method corresponding to the HTTP Method, the request under that Method will return HTTP Status 404.

warning

GoFrame's RESTful object registration method is a strict REST route registration method. We can consider the controller's object as the resource in REST, and the HTTP Method methods as the resource operation methods in the REST specification. If you are not very familiar with the REST specification or do not want a very strict RESTful routing design, please ignore this section.

We can complete the REST object registration using the BindObjectRest method, as shown in the example:

package main

import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)

type Controller struct{}

// RESTFul - GET
func (c *Controller) Get(r *ghttp.Request) {
r.Response.Write("GET")
}

// RESTFul - POST
func (c *Controller) Post(r *ghttp.Request) {
r.Response.Write("POST")
}

// RESTFul - DELETE
func (c *Controller) Delete(r *ghttp.Request) {
r.Response.Write("DELETE")
}

// This method cannot be mapped and will not be accessible
func (c *Controller) Hello(r *ghttp.Request) {
r.Response.Write("Hello")
}

func main() {
s := g.Server()
c := new(Controller)
s.BindObjectRest("/object", c)
s.SetPort(8199)
s.Run()
}

Upon execution, the terminal outputs the route table as follows:

SERVER | DOMAIN  | ADDRESS | METHOD |  ROUTE  |          HANDLER          | MIDDLEWARE
|---------|---------|---------|--------|---------|---------------------------|------------|
default | default | :8199 | DELETE | /object | main.(*Controller).Delete |
|---------|---------|---------|--------|---------|---------------------------|------------|
default | default | :8199 | GET | /object | main.(*Controller).Get |
|---------|---------|---------|--------|---------|---------------------------|------------|
default | default | :8199 | POST | /object | main.(*Controller).Post |
|---------|---------|---------|--------|---------|---------------------------|------------|

Constructor Method Init and Destructor Method Shut

The Init and Shut methods in objects are special methods that are automatically invoked by the Server during the HTTP request process (similar to constructor and destructor functions).

  1. Init Callback Method

A method for initialization when the object receives a request, which is called back before the service API is invoked.

Method definition:

// "Constructor" object method
func (c *Controller) Init(r *ghttp.Request) {

}
  1. Shut Callback Method

Automatically called by the Server when the request ends, which can be used for the object to perform some cleanup operations.

Method definition:

// "Destructor" object method
func (c *Controller) Shut(r *ghttp.Request) {

}

Let's look at an example:

package main

import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)

type Controller struct{}

func (c *Controller) Init(r *ghttp.Request) {
r.Response.Writeln("Init")
}

func (c *Controller) Shut(r *ghttp.Request) {
r.Response.Writeln("Shut")
}

func (c *Controller) Hello(r *ghttp.Request) {
r.Response.Writeln("Hello")
}

func main() {
s := g.Server()
c := new(Controller)
s.BindObject("/object", c)
s.SetPort(8199)
s.Run()
}

After execution, the terminal route table output is as follows:

SERVER | DOMAIN  | ADDRESS | METHOD |     ROUTE     |         HANDLER          | MIDDLEWARE
|---------|---------|---------|--------|---------------|--------------------------|------------|
default | default | :8199 | ALL | /object/hello | main.(*Controller).Hello |
|---------|---------|---------|--------|---------------|--------------------------|------------|

As shown, Init and Shut are not automatically registered as route methods, and when accessing http://127.0.0.1:8199/object/hello, the output result will be:

Hello
Shut