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

The GoFrame framework provides a standardized routing approach that simplifies route registration and lets developers focus on business logic. We call this Standard Routing - a more intuitive and maintainable way to handle HTTP endpoints.

Defining Request/Response Types​

Standard routing uses structured types for both requests and responses. This approach enables parameter validation, documentation generation, and future extensibility:

type HelloReq struct {
g.Meta `path:"/" method:"get"`
Name string `v:"required" dc:"User's name"`
Age int `v:"required" dc:"User's age"`
}
type HelloRes struct {}

Key components:

  • The request struct embeds g.Meta with routing metadata tags:
    • path: The URL path to register
    • method: The HTTP method to handle (GET, POST, etc.)
  • Field tags provide additional functionality:
    • v: Validation rules (short for "valid"). Here, v:"required" marks fields as mandatory
    • dc: Documentation comments (short for "description") for API docs
info

For a complete reference of available tags and validation rules, check out the relevant chapters in our development manual. For now, just focus on understanding their basic purpose.

Object-Oriented Route Handlers​

For better maintainability, especially in larger APIs, we use an object-oriented approach instead of registering routes one by one. Here's how it works:

type Hello struct{}

func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
r := g.RequestFromCtx(ctx)
r.Response.Writef(
"Hello %s! Your Age is %d",
req.Name,
req.Age,
)
return
}

Benefits of this approach:

  • Routes are organized into logical groups via handler objects
  • Method signatures are more idiomatic and business-focused compared to raw func(*ghttp.Request) handlers
  • The original request object is still accessible via g.RequestFromCtx when needed

Complete Example​

Here's how we'd rewrite our web server using standard routing:

main.go
package main

import (
"context"

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

type HelloReq struct {
g.Meta `path:"/" method:"get"`
Name string `v:"required" dc:"User's name"`
Age int `v:"required" dc:"User's age"`
}
type HelloRes struct{}

type Hello struct{}

func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
r := g.RequestFromCtx(ctx)
r.Response.Writef(
"Hello %s! Your Age is %d",
req.Name,
req.Age,
)
return
}

func main() {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Bind(
new(Hello),
)
})
s.SetPort(8000)
s.Run()
}

Key points:

  • s.Group creates a route group with a common prefix ("/" in this case)
  • group.Bind registers all public methods of our handler object automatically, using struct metadata to configure routes

Testing the API​

Let's test with valid parameters at http://127.0.0.1:8000/?name=john&age=18:

img.png

When we try an invalid request at http://127.0.0.1:8000/, we get no output. This is because the validation failed before reaching our handler - the server rejected the request due to missing required parameters.

What's Next?​

While we've improved our routing structure, we still need better control over error handling. For example, how can we:

  • Capture and customize validation error messages?
  • Format error responses consistently?

We'll tackle these questions in the next chapter.