golang基于NATS构建实时REST服务同步插件库go-res的使用

Golang基于NATS构建实时REST服务同步插件库go-res的使用

概述

go-res是一个Go语言包,用于创建REST、实时和RPC API,通过Resgate无缝同步所有响应式Web客户端。

Resgate logo

安装

go get github.com/jirenius/go-res

快速入门示例

package main

import res "github.com/jirenius/go-res"

func main() {
   s := res.NewService("example")
   s.Handle("model",
      res.Access(res.AccessGranted),
      res.GetModel(func(r res.ModelRequest) {
         r.Model(struct {
            Message string `json:"message"`
         }{"Hello, World!"})
      }),
   )
   s.ListenAndServe("nats://localhost:4222")
}

前提条件

需要安装NATS Server和Resgate,可以通过以下Docker命令完成:

docker network create res
docker run -d --name nats -p 4222:4222 --net res nats
docker run --name resgate -p 8080:8080 --net res resgateio/resgate --nats nats://nats:4222

完整示例

创建新服务

s := res.NewService("myservice")

添加模型资源处理程序

mymodel := map[string]interface{}{"name": "foo", "value": 42}
s.Handle("mymodel",
   res.Access(res.AccessGranted),
   res.GetModel(func(r res.ModelRequest) {
      r.Model(mymodel)
   }),
)

添加集合资源处理程序

mycollection := []string{"first", "second", "third"}
s.Handle("mycollection",
   res.Access(res.AccessGranted),
   res.GetCollection(func(r res.CollectionRequest) {
      r.Collection(mycollection)
   }),
)

添加参数化资源处理程序

s.Handle("article.$id",
   res.Access(res.AccessGranted),
   res.GetModel(func(r res.ModelRequest) {
      article := getArticle(r.PathParam("id"))
      if article == nil {
         r.NotFound()
      } else {
         r.Model(article)
      }
   }),
)

添加方法调用处理程序

s.Handle("math",
   res.Access(res.AccessGranted),
   res.Call("double", func(r res.CallRequest) {
      var p struct {
         Value int `json:"value"`
      }
      r.ParseParams(&p)
      r.OK(p.Value * 2)
   }),
)

发送模型更新变更事件

s.With("myservice.mymodel", func(r res.Resource) {
   mymodel["name"] = "bar"
   r.ChangeEvent(map[string]interface{}{"name": "bar"})
})

发送集合更新添加事件

s.With("myservice.mycollection", func(r res.Resource) {
   mycollection = append(mycollection, "fourth")
   r.AddEvent("fourth", len(mycollection)-1)
})

添加认证处理程序

s.Handle("myauth",
   res.Auth("login", func(r res.AuthRequest) {
      var p struct {
         Password string `json:"password"`
      }
      r.ParseParams(&p)
      if p.Password != "mysecret" {
         r.InvalidParams("Wrong password")
      } else {
         r.TokenEvent(map[string]string{"user": "admin"})
         r.OK(nil)
      }
   }),
)

添加访问控制处理程序

s.Handle("mymodel",
   res.Access(func(r res.AccessRequest) {
      var t struct {
         User string `json:"user"`
      }
      r.ParseToken(&t)
      if t.User == "admin" {
         r.AccessGranted()
      } else {
         r.AccessDenied()
      }
   }),
   res.GetModel(func(r res.ModelRequest) {
      r.Model(mymodel)
   }),
)

使用路由

s.Route("v2", func(m *res.Mux) {
   m.Handle("mymodel",
      /* ... */
   )
})

启动服务

s.ListenAndServe("nats://localhost:4222")

测试

restest子包用于测试服务和验证响应。

服务间通信

resprot子包提供了通过NATS服务器与其他服务通信的低级结构和方法。

存储

store子包包含用于处理数据库存储的处理程序和接口。

贡献

go-res包仍在开发中,但API基本已确定。对包API或其实现的任何反馈都非常感谢!


更多关于golang基于NATS构建实时REST服务同步插件库go-res的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于NATS构建实时REST服务同步插件库go-res的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用NATS构建实时REST服务:go-res库指南

介绍

go-res是一个基于NATS的实时REST服务同步插件库,它允许开发者轻松构建实时应用程序后端。通过结合NATS的消息传递能力和RESTful接口,go-res提供了高效的实时数据同步解决方案。

核心概念

  1. 资源(Resource): 应用程序中的基本数据单元
  2. 模型(Model): 资源的持久化表示
  3. 集合(Collection): 资源的聚合

安装

首先安装必要的依赖:

go get github.com/nats-io/nats.go
go get github.com/jirenius/go-res

基本使用示例

1. 初始化服务

package main

import (
	"log"
	"github.com/jirenius/go-res"
	"github.com/nats-io/nats.go"
)

func main() {
	// 连接到NATS服务器
	nc, err := nats.Connect(nats.DefaultURL)
	if err != nil {
		log.Fatal(err)
	}
	defer nc.Close()

	// 创建res服务
	s := res.NewService("example")
	s.SetConnection(nc)

	// 添加处理程序
	s.Handle("model",
		res.Access(res.AccessGranted),
		res.GetModel(func(r res.ModelRequest) {
			r.Model(map[string]interface{}{
				"id":    "123",
				"title": "Example Model",
			})
		}),
	)

	// 启动服务
	if err := s.Start(); err != nil {
		log.Fatal(err)
	}

	// 保持程序运行
	select {}
}

2. 定义资源模型

type User struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

func (u *User) ToMap() map[string]interface{} {
	return map[string]interface{}{
		"id":    u.ID,
		"name":  u.Name,
		"email": u.Email,
	}
}

func getUserModelHandler(userStore map[string]*User) res.ModelHandlerFunc {
	return func(r res.ModelRequest) {
		id := r.PathParam("id")
		if user, ok := userStore[id]; ok {
			r.Model(user.ToMap())
		} else {
			r.NotFound()
		}
	}
}

3. 实时集合示例

func setupUserService(s *res.Service, userStore map[string]*User) {
	s.Handle("users",
		res.Access(res.AccessGranted),
		res.GetCollection(func(r res.CollectionRequest) {
			users := make([]interface{}, 0, len(userStore))
			for _, u := range userStore {
				users = append(users, res.Ref("user."+u.ID))
			}
			r.Collection(users)
		}),
	)

	s.Handle("user.$id",
		res.Access(res.AccessGranted),
		res.GetModel(getUserModelHandler(userStore)),
		res.Call("update", func(r res.CallRequest) {
			var params map[string]interface{}
			r.ParseParams(&params)
			
			id := r.PathParam("id")
			if user, ok := userStore[id]; ok {
				if name, ok := params["name"].(string); ok {
					user.Name = name
				}
				if email, ok := params["email"].(string); ok {
					user.Email = email
				}
				
				// 通知所有订阅者变更
				s.With("user."+id).Event("change", user.ToMap())
				r.OK(nil)
			} else {
				r.NotFound()
			}
		}),
	)
}

4. 事件订阅

客户端可以通过NATS订阅资源变更事件:

func subscribeToUserChanges(nc *nats.Conn, userID string) {
	sub, err := nc.Subscribe("event.user."+userID+".change", func(msg *nats.Msg) {
		log.Printf("User changed: %s", string(msg.Data))
	})
	if err != nil {
		log.Fatal(err)
	}
	defer sub.Unsubscribe()
}

高级特性

1. 访问控制

s.Handle("admin.users",
	res.Access(func(r res.AccessRequest) {
		if r.AuthToken() == "admin-secret" {
			r.AccessGranted()
		} else {
			r.AccessDenied()
		}
	}),
	// ...其他处理程序
)

2. 查询参数支持

s.Handle("articles",
	res.GetCollection(func(r res.CollectionRequest) {
		query := r.Query()
		author := query.Get("author")
		category := query.Get("category")
		
		// 根据查询参数过滤文章
		filtered := filterArticles(author, category)
		r.Collection(filtered)
	}),
)

3. 错误处理

s.Handle("secure.data",
	res.GetModel(func(r res.ModelRequest) {
		if !isAuthorized(r) {
			r.Error(res.ErrUnauthorized)
			return
		}
		// ...处理请求
	}),
)

最佳实践

  1. 资源命名: 使用清晰的命名约定(如module.entity
  2. 事件粒度: 保持事件小而具体
  3. 批处理: 对频繁更新使用批处理事件
  4. 监控: 监控NATS和服务指标

总结

go-res结合NATS提供了强大的实时REST服务构建能力。通过资源模型和事件系统,开发者可以轻松实现数据同步和实时更新功能。这种架构特别适合需要低延迟和高并发的应用场景。

要了解更多细节,建议查阅go-res的官方文档和示例代码库。

回到顶部