Go package implementing the RES-Service Protocol. Used to create REST, real time, and RPC APIs, where all your reactive web clients are synchronized seamlessly through Resgate.
Visit Resgate.io for more information.
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(map[string]string{
"message": "Hello, World!",
})
}),
)
s.ListenAndServe("nats://localhost:4222")
}
Example | Description |
---|---|
Edit Text | Text field that can be edited by multiple clients concurrently. |
Edit Text BadgerDB | Edit Text example using BadgerDB middleware to persist all changes. |
Book Collection | List of book titles & authors that can be edited by many. |
Book Collection BadgerDB | Book Collection example using BadgerBD middleware to persist all changes. |
Note
Above examples are complete with both service and client.
The middleware
sub-package contains middleware that adds handler functions to a res.Handler
, to perform tasks such as:
- storing, loading and updating persisted data
- synchronize changes between multiple service instances
- provide helpers for complex live queries
Name | Description |
---|---|
middleware.BadgerDB |
Stores and updates resources in a BadgerDB using the events. |
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)
}),
)
A change event will update the model on all subscribing clients.
s.With("myservice.mymodel", func(r res.Resource) {
mymodel["name"] = "bar"
r.ChangeEvent(map[string]interface{}{"name": "bar"})
})
An add event will update the collection on all subscribing clients.
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")
Inspiration on the go-res API has been taken from github.com/go-chi/chi, a great package when writing ordinary HTTP services, and will continue to do so when it is time to implement Middleware, sub-handlers, and mounting.
The go-res package is still under development, and commits may still contain breaking changes. It should only be used for educational purpose. Any feedback on the package API or its implementation is highly appreciated!
If you find any issues, feel free to report them as an issue.