go-sail is a lightweight progressive web framework implemented using Go language. It is not the product of reinventing the wheel, but stands on the shoulders of giants and integrates existing excellent components to help users build stable and reliable services in the simplest way. As its name suggests, you can regard it as the beginning of your own journey in the Golang ecosystem. go-sail will help you start lightly and set sail.
go version >= 1.23
go get -u github.com/keepchen/go-sail/v3
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/keepchen/go-sail/v3/sail"
"github.com/keepchen/go-sail/v3/sail/config"
)
var (
conf = &config.Config{}
registerRoutes = func(ginEngine *gin.Engine) {
ginEngine.GET("/hello", func(c *gin.Context){
c.String(http.StatusOK, "%s", "hello, world!")
})
}
)
func main() {
sail.WakeupHttp("go-sail", conf).Hook(registerRoutes, nil, nil).Launch()
}Console screenshot after launched like this:
parseFn := func(content []byte, viaWatch bool){
fmt.Println("config content: ", string(content))
if viaWatch {
//reload config...
}
}
etcdConf := etcd.Conf{
Endpoints: []string{""},
Username: "",
Password: "",
}
key := "go-sail.config.yaml"
sail.Config(parseFn).ViaEtcd(etcdConf, key).Parse(parseFn)func UserRegisterSvc(c *gin.Context) {
...
sail.LogTrace(c).Warn("log something...")
...
}- Issue token
func UserLoginSvc(c *gin.Context) {
...
uid := "user-1000"
exp := time.Now().Add(time.Hour * 24).Unix()
otherFields := map[string]interface{}{
"nickname": "go-sail",
"avatar": "https://go-sail.dev/assets/avatar/1.png",
...
}
ok, token, err := sail.JWT().MakeToken(uid, exp, otherFields)
...
}- Authentication
func UserInfoSvc(c *gin.Context) {
...
ok, claims, err := sail.JWT().ValidToken(token)
...
}func UserInfoSvc(c *gin.Context) {
sail.Response(c).Wrap(constants.ErrNone, resp).Send()
}- Read / Write
func UserInfoSvc(c *gin.Context) {
uid := "user-1000"
var user models.User
//READ: query user info
sail.GetDBR().Where("uid = ?", uid).First(&user)
...
//WRITE: update user info
sail.GetDBW().Model(&models.User{}).
Where("uid = ?", uid).
Updates(map[string]interface{}{
"avatar": "https://go-sail.dev/assets/avatar/2.png"
})
}- Transaction
func UserInfoSvc(c *gin.Context) {
uid := "user-1000"
err := sail.GetDBW().Transaction(func(tx *gorm.DB){
e1 := tx.Model(&models.User{}).
Where("uid = ?", uid).
Updates(map[string]interface{}{
"avatar": "https://go-sail.dev/assets/avatar/2.png"
}).Error
if e1 != nil {
return e1
}
e2 := tx.Create(&models.UserLoginHistory{
Uid: uid,
...
}).Error
return e2
})
}func UserInfoSvc(c *gin.Context) {
...
sail.GetRedis().Set(ctx, "go-sail:userInfo", "user-1000", time.Hour*24).Result()
...
}- RSA
sail.Password().RSAEncrypt(plaintext, publicKey) // Deprecated: PKCS #1 v1.5 encryption is unsafe. Use EncryptOAEP for new data.
sail.Password().RSADecrypt(encryptedStr, privateKey) // Deprecated: PKCS #1 v1.5 decryption is unsafe. Use DecryptOAEP for OAEP ciphertext.
sail.Password().RSAEncryptOAEP(plaintext, publicKey)
sail.Password().RSADecryptOAEP(encryptedStr, privateKey)- Bcrypt
sail.Password().BcryptHashMake(plaintext)
sail.Password().BcryptHashCheck(plaintext, hash)- Argon2
sail.Password().Argon2HashMake(plaintext)
sail.Password().Argon2HashCheck(plaintext, hash)- Aes
sail.Password().AesGCMEncrypt(plaintext, key)
sail.Password().AesGCMDecrypt(ciphertext, key)- SM4
sail.Password().SM4GCMEncrypt(plaintext, key)
sail.Password().SM4GCMDecrypt(ciphertext, key)- Interval
func TodoSomething() {
fn := func() { ... }
sail.Schedule("todoSomething", fn).Daily()
}- Linux Crontab style
func TodoSomething() {
fn := func() { ... }
sail.Schedule("todoSomething", fn).RunAt("*/5 * * * *")
}- Race detection
func TodoSomething() {
fn := func() { ... }
sail.Schedule("todoSomething", fn).Withoutoverlapping().RunAt("*/5 * * * *")
}func UpdateUserBalance() {
if !sail.RedisLocker().TryLock(key) {
return false
}
defer sail.RedisLocker().Unlock(key)
...
}- HTTP Responder
- Uniform Response Fields
- Managing HTTP status codes
- Management business code
- Components
- Database
- Jwt
- Kafka
- Logger
- Nacos
- Etcd
- Nats
- Redis
- Valkey
- Service Registration and Discovery
- Nacos
- Etcd
- Toolkit
- Encryption and Decryption
- File
- IP
- String
- Random number
- Date and Time
- ...
- Log collection and export
- Local files
- Exporter
- Redis
- Kafka
- Nats
- Scheduled Tasks
- Cancellable
- Disposable
- Periodic
- Linux Crontab style
- Race Detection
- Telemetry and Observability
- Call chain tracing
- Prometheus
- Pprof
- Log Exporter
- Performance monitor
- Prometheus
- Pprof
- Distributed Quantile Statistics
- P99
- P90
- ...
- P(N)
- API error codes
- Dynamic injection
- Internationalization
- Distributed lock based on Redis
- Blocking
- None-Blocking
- API Documentation
- Redocly
- Swagger
- Configuration
- File
- Etcd
- Nacos
ulimit -n 65535 && sh run_benchmark.shTest results (real HTTP requests)
goos: darwin
goarch: amd64
pkg: github.com/keepchen/go-sail/v3
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkGoSailParallel-12 88252 12898 ns/op 8860 B/op 92 allocs/op
BenchmarkGinParallel-12 96548 11722 ns/op 7187 B/op 82 allocs/op
PASS
ok github.com/keepchen/go-sail/v3 3.663s
Thank you to everyone who provided valuable suggestions and comments during the experience and use, as well as provided other kinds of help!
- Configuration modular optimization proposal @fujilin
- Responder syntax sugar enhancement optimization proposal @lichuanzhang
- Logo beautification @ShuaiRen34
- PR is welcome: pull request
- Issue is welcome: issue
- Thank you for your star if you like this project :)
| Logo | URL | Category | Industry |
|
https://fsx120.cn | Website | Medical |
|
https://sendflare.com | Website | SaaS |
|
https://stardots.io | Website | SaaS |
|
https://t.me/PiggyPiggyofficialbot | Telegram miniprogram | Web3 GameFi |
|
- | Wechat miniprogram | Lifestyle services |
|
- | Website | Web3 GameFi |
|
- | Website | Web3 GameFi |
|
- | Website | Web3 GameFi |
|
|
|
|









