# Beerus
# Installing dependencies
go get github.com/Beerus-go/Beerus@v1.1.9
# The underlying technology used
- http uses the net/http package that comes with go, and extends the way routes are managed on top of it.
- WebSocket is an extension of http, the framework itself implements the protocol upgrade, message listening, message parsing, message sending and other functions
- udp is developed based on the net package, with a simple secondary wrapper
In addition to the underlying technologies described above, there are many other extensions, which you can learn about by reading the documentation below
# HTTP Service
# Create Route
- Simply call the functions below the route, choosing the most appropriate function for the type of request you need
- The first parameter is the URL of the route, which is the address requested by the front-end
- The second parameter is a function that will be automatically executed by the server when the front-end requests this URL
- The second parameter (function) must have a return value, the supported types are: struct, map, array, beerus will automatically convert the return value into a Json response to the front end, here for the sake of demonstration convenience to use the map
- If you don't like this type of response, or you don't intend to use JSON to interact with the front-end in your project, then you can turn off JSON mode, which will be discussed later
func CreateRoute() {
// post route example
route.POST("/example/post", func (req commons.BeeRequest, res commons.BeeResponse) map[string]string {
msg := make(map[string]string)
msg["msg"] = "success"
return param
})
// get route example
route.GET("/example/get", func (req commons.BeeRequest, res commons.BeeResponse) map[string]string{
msg := make(map[string]string)
msg["msg"] = "success"
return param
})
}
# Using the traditional way of getting parameters
// Get the parameters from the front end, regardless of the request method
req.FormValue("param name")
// Get multiple parameters with the same name, return an array, only works for x-www-form-urlencoded, GET requests, FormData can only get one value
req.FormValues("param name")
// Get the request header from the front end, regardless of the request method
req.HeaderValue("header name")
// Get the file from the front-end, form-data only
req.GetFile("param name")
// Get the json string passed as json
req.Json
# Extract parameters directly to struct
First, you need to define a struct, The matching rules are as follows
- If the field attribute is set in the tag, it will be matched against the field first, if not then it will be matched against the field name again.
- The supported types are shown in the following examples
- commons.BeeFile type Only works on formdata
- []string Only available for x-www-form-urlencoded, JSON, GET requests, FormData can only get one value.
// DemoParam If you have a struct like this, and you want to put all the parameters from the request into this struct
type DemoParam struct {
// You can customize any field
// the name of the field must be exactly the same as the name of the requested parameter, and is case-sensitive
TestStringReception string `field:"testStringReception"`
TestIntReception int `field:"testIntReception"`
TestInt64Reception int64
TestUintReception uint
TestUint32Reception uint32
TestUint64Reception uint64
TestFloatReception float32
TestStringRegReception string
TestBoolReception bool
TestBeeFileReception commons.BeeFile
TestReception []string
}
Then, use this struct as a parameter to the routing function
- The number of parameters of the routing function is unlimited, you can set only one struct or multiple structs, or you can mix them with request and response as in the example
// Note the first parameter
route.POST("/example/post", func(param DemoParam, req commons.BeeRequest, res commons.BeeResponse) map[string]string {
println(param.TestStringReception)
println(param.TestIntReception)
println(param.TestInt64Reception)
println(param.TestFloatReception)
println(param.TestUintReception)
println(param.TestUint64Reception)
println(param.TestBoolReception)
msg := make(map[string]string)
msg["msg"] = "success"
return param
})
Can also be extracted manually, call the params.ToStruct function to extract all the parameters from req to struct
- The first argument is req
- the second argument is a pointer to struct
When the params.ToStruct function is finished, there will be data in param
param := DemoParam{}
// Extraction parameters, Generally used in scenarios where verification is not required or you want to verify manually
params.ToStruct(req, ¶m)
# Launching services
You need to call the route creation function manually
func main() {
// Interceptors, routes, etc. Loading of data requires its own calls
routes.CreateRoute()
// Listen the service and listen to port 8080
beerus.ListenHTTP(8080)
}
Once the service is started, it can be accessed normally, by http://ip:port/routePath
# Parameter validation
To achieve automatic parameter validation, the parameters must first be extracted to struct, and the validation method is simple, see the following example
- notnull: Set to true to indicate that this parameter must not be empty
- reg: Write your own regular expression that fails to validate when it does not match.
- max: Maximum value of the field
- min: Minimum value of the field
- msg: The message returned when the verification does not pass
- notnull, reg valid only for string, max, min valid only for numeric fields
- routes: Used to set which routes this validation is valid for, multiple comma-separated, supports * wildcards
type DemoParam struct {
// You can customize any field
// the name of the field must be exactly the same as the name of the requested parameter, and is case-sensitive
TestStringReception string `notnull:"true" msg:"TestStringReception Cannot be empty" routes:"/example/put"`
TestIntReception int `max:"123" min:"32" msg:"TestIntReception The value range must be between 32 - 123" routes:"/example/post"`
TestInt64Reception int64 `max:"123" min:"32" msg:"TestInt64Reception The value range must be between 32 - 123"`
TestUintReception uint `max:"123" min:"32" msg:"TestUintReception The value range must be between 32 - 123"`
TestUint32Reception uint32 `max:"123" min:"32" msg:"TTestUint32Reception The value range must be between 32 - 123"`
TestUint64Reception uint64 `max:"123" min:"32" msg:"TestUint64Reception The value range must be between 32 - 123"`
TestFloatReception float32 `max:"123" min:"32" msg:"TestFloatReception The value range must be between 32 - 123"`
TestStringRegReception string `reg:"^[a-z]+$" msg:"TestStringRegReception Does not meet the regular"`
}
Once the above has been configured, parameter validation will automatically take effect and a json message will be automatically returned to the front-end if the validation does not pass
{"code":1128, "msg":"The msg you set in the validation tag"}
# Exception handling mechanism
- In development, we often give the front-end some error messages, according to the conventional practice, we need to manually return the message in the if, but this is not very elegant way to write
- We can use error in go to achieve this
- Set a second return value for the routing function, which must be of type error
// post route example
route.POST("/example/post", func (req commons.BeeRequest, res commons.BeeResponse) (map[string]string, error) {
if xxx {
return nil, errors.New("The error message you want to return to the front-end")
}
msg := make(map[string]string)
msg["msg"] = "success"
return param, nil
})
# File download
// Example of file download
route.GET("/downLoad/file", func(req commons.BeeRequest, res commons.BeeResponse) string {
file, err := ioutil.ReadFile("/Users/yeyu/Downloads/goland-2021.2.4.dmg")
if err == nil {
}
// Writing files to the client
res.SendStream("goland.dmg", file)
// Just return this constant
return web.Download
})
# Turn off JSON mode
It's easy to turn off, just add the following code before creating the route
route.JsonMode = false
Once JSON mode is turned off, automatic validation will not work as beerus cannot predict what type of data you intend to return to the front end, so the developer will need to manually call a function to validate
- In your route, add the following code to implement parameter validation
// Validation function is called with the second parameter being a pointer to the struct from which the request parameters were extracted
var result = params.Validation(req, ¶m)
// When the return is not SUCCESS, it means that the validation did not pass
if result != params.SUCCESS {
// Here you can choose the appropriate SendXXX function yourself
res.SendErrorMsg(1128, result)
return
}
- The routing function cannot have a return value and must call the SendXXX function inside res to respond to the front-end data
// post route example
route.POST("/example/post", func (req commons.BeeRequest, res commons.BeeResponse) {
res.SendText("text")
})
- Returning data to the client
// Return json to client
res.SendJson("json")
// Return text to client
res.SendText("text")
// Return html to client
res.SendHtml("html text")
// Returning files to the client
res.SendStream("filename", []byte)
// Return other custom content-type data to the client
res.SendData("data")
# Interceptors
- Creating an interceptor is particularly similar to creating a route, just call the route.AddInterceptor function
- The first parameter is the path of the route to be intercepted and supports * wildcards
- The second parameter is a function that implements the interceptor logic
- Returns true directly if it passes, false otherwise
Points to note:
If you return false in the interceptor, it's important to call the res.SendXXX function to give the front-end a response, otherwise the request will block until it times out, with a performance impact
// This function needs to be called in the main function
func CreateInterceptor() {
route.AddInterceptor("/example/*", loginInterceptorBefore)
}
func loginInterceptorBefore(req *commons.BeeRequest, res *commons.BeeResponse) bool {
res.SetHeader("hello", "hello word").SetHeader("hello2", "word2")
log.Println("exec interceptor")
return true
}
# Session management
You need to create a session first
- Secret: encryption key, length must be = 32
- InitializationVector: initialization constant, length must be = 16
- Timeout: duration of the session, in milliseconds
session := new(commons.BeeSession)
session.Secret = "12345678abcdefgh09876543alnkdjfh"
session.InitializationVector = "12345678qwertyui"
session.Timeout = 3000
Then you can use the session to create a token
- Give the token to the front-end, which will bring it back with each request
demo := Demo{}
demo.Name = "Beerus"
demo.Age = 18
demo.Height = 180
token, err := session.CreateToken(demo)
Restore the token to its original data
demo2 := Demo{}
err = session.RestoreToken(token, &demo2)
# WebSocket Service
# Create route
- Only three functions are used here, in practice it is possible to use three different functions for each route
- The first parameter session: there are just two elements in it, an ID and a SendString, Send function
- The second parameter msg: is the message sent by the client, which can be used directly
// CreateWebSocketRoute Creating websocket routes
func CreateWebSocketRoute() {
wroute.AddWebSocketRoute("/ws/test", onConnection, onMessage, onClose)
wroute.AddWebSocketRoute("/ws/test2", onConnection, onMessage, onClose)
}
// In order to save time, only three functions are used below. In practice, you can configure a set of functions for each route
func onConnection(session *wparams.WebSocketSession, msg string) {
println(msg + "-------------------------------")
session.SendString("connection success")
}
func onMessage(session *wparams.WebSocketSession, msg string) {
println(msg + "-------------------------------")
session.SendString("I got the message.")
}
func onClose(session *wparams.WebSocketSession, msg string) {
println(msg + "-------------------------------")
}
# Launching services
You need to call the route creation function manually, the service started is still an HTTP service
func main() {
// Interceptors, routes, etc. Loading of data requires its own calls
routes.CreateWebSocketRoute()
// Listen the service and listen to port 8080
beerus.ListenHTTP(8080)
}
Once started, you can launch WebSocket communication normally, with the connection method: ws://ip:port/route path
# UDP Service
# Launching services
- There is no concept of routing, only a function to receive data
- The first parameter is the handler
- The second parameter is the data separator
- The third parameter is the port
func main() {
// Listening to a UDP service
// The first parameter is the handler
// The second parameter is the data separator
// The third parameter is the port
beerus.ListenUDP(updHandler, []byte("|"), 8080)
}
func updHandler(data []byte) {
// data is the data you received
println(util.BytesToString(data))
}
Once the data is received, it can be converted directly to string