RESTCONF client
Connecting to a RESTCONF server
You can communicate with a RESTCONF server using a basic HTTP library. For simple applications this is a reasonable approach. If you want to “level-up” your API access to be able to walk the schema (i.e. YANG) then you can use the RESTCONF client in FreeCONF.
package demo
import (
"fmt"
"strings"
"testing"
"github.com/freeconf/examples/car"
"github.com/freeconf/restconf"
"github.com/freeconf/restconf/client"
"github.com/freeconf/restconf/device"
"github.com/freeconf/yang/fc"
"github.com/freeconf/yang/node"
"github.com/freeconf/yang/nodeutil"
"github.com/freeconf/yang/source"
)
func connectClient() {
// YANG: just need YANG file ietf-yang-library.yang, not the yang of remote system as that will
// be downloaded as needed
ypath := restconf.InternalYPath
// Connect
proto := client.ProtocolHandler(ypath)
dev, err := proto("http://localhost:9998/restconf")
if err != nil {
panic(err)
}
// Get a browser to walk server's management API for car
car, err := dev.Browser("car")
if err != nil {
panic(err)
}
root := car.Root()
defer root.Release()
// Example of config: I feel the need, the need for speed
// bad config is rejected in client before it is sent to server
n, err := nodeutil.ReadJSON(`{"speed":100}`)
if err != nil {
panic(err)
}
err = root.UpsertFrom(n)
if err != nil {
panic(err)
}
// Example of metrics: Get all metrics as JSON
sel, err := root.Find("?content=nonconfig")
if err != nil {
panic(err)
}
defer sel.Release()
metrics, err := nodeutil.WriteJSON(sel)
if err != nil {
panic(err)
}
if metrics == "" {
panic("no metrics")
}
// Example of RPC: Reset odometer
sel, err = root.Find("reset")
if err != nil {
panic(err)
}
defer sel.Release()
if _, err = sel.Action(nil); err != nil {
panic(err)
}
// Example of notification: Car has an important update
sel, err = root.Find("update")
if err != nil {
panic(err)
}
defer sel.Release()
unsub, err := sel.Notifications(func(n node.Notification) {
msg, err := nodeutil.WriteJSON(n.Event)
if err != nil {
panic(err)
}
fmt.Println(msg)
})
if err != nil {
panic(err)
}
defer unsub()
// Example of multiple modules: This is the FreeCONF server module
rcServer, err := dev.Browser("fc-restconf")
if err != nil {
panic(err)
}
// Example of config: Enable debug logging on FreeCONF's remote RESTCONF server
serverSel := rcServer.Root()
defer serverSel.Release()
n, err = nodeutil.ReadJSON(`{"debug":true}`)
if err != nil {
panic(err)
}
serverSel.UpsertFrom(n)
if err != nil {
panic(err)
}
}
func TestClient(t *testing.T) {
// setup - start a server
ypath := source.Path("../yang")
serverYPath := source.Any(ypath, restconf.InternalYPath)
carServer := car.New()
local := device.New(serverYPath)
local.Add("car", car.Manage(carServer))
s := restconf.NewServer(local)
defer s.Close()
cfg := `{
"fc-restconf": {
"debug": true,
"web" : {
"port": ":9998"
}
},
"car" : {
"speed": 5
}
}`
fc.RequireEqual(t, nil, local.ApplyStartupConfig(strings.NewReader(cfg)))
connectClient()
}