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.
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
.
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
.
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).
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) {
}
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