34
More Go RPC, using gorilla/rpc/json
Following on from an earlier post about Go and RPC, this time we're looking at gorilla/rpc
and gorilla/rpc/json
. One weakness of the prior example in the post linked above was it required both parts, client and server to be written in Go, a tight coupling not immediately apparent to someone learning either Go or RPC. Enter JSON...
Using JSON allows us to send a request as JSON and receive a response as JSON thus removing a tight coupling that we had previously.
OK let's get started. You're going to need a project structure much like below, obviously the modules
files are optional if you're a GOPATH
user and you don't strictly need a readme
but you should by force of habit include one in your projects.
gorilla-jsonrpc-demo
├── go.mod
├── go.sum
├── projects.json
├── readme.md
└── server
└── main.go
go get github.com/gorilla/rpc
go get -u github.com/gorilla/mux
Here I've created a dummy data file with some sample projects structures in it. Extremely trivial to avoid complicating the demo.
[
{
"name": "go/golang",
"author": "google",
"stars": "88200",
"forks": "12900"
},
{
"name": "chi",
"author": "go-chi",
"stars": "9800",
"forks": "665"
},
{
"name": "go-me",
"author": "me",
"stars": "1",
"forks": "0"
},
{
"name": "go-you",
"author": "you",
"stars": "100",
"forks": "10"
},
{
"name": "go-them",
"author": "them",
"stars": "2000",
"forks": "112"
}
]
You can adapt your file, structures to suit your case or just to play around with more complex structures.
We're going to make a couple of changes to the previous server we wrote and although the changes are slight they make a world difference.
package main
import (
jsonparse "encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"github.com/gorilla/mux"
"github.com/gorilla/rpc"
"github.com/gorilla/rpc/json"
)
type Args struct {
Name string
}
type Repo struct {
Name string `json:"name,omitempty"`
Author string `json:"author,omitempty"`
Forks string `json:"forks,omitempty"`
Stars string `json:"stars,omitempty"`
}
type JSONServer struct{}
func (t *JSONServer) GiveRepoDetails(r *http.Request, args *Args, reply *Repo) error {
var repos []Repo
// get the datafile
absPath, _ := filepath.Abs("projects.json")
raw, readerr := ioutil.ReadFile(absPath)
if readerr != nil {
log.Println("error:", readerr)
os.Exit(1)
}
// unmarshal the raw data from the file into our array for the repos
marshalerr := jsonparse.Unmarshal(raw, &repos)
if marshalerr != nil {
log.Println("error:", marshalerr)
os.Exit(1)
}
for _, repo := range repos {
if repo.Name == args.Name {
// we found a hit
fmt.Println(repo)
*reply = repo
break
}
}
return nil
}
func main() {
port := ":8080"
s := rpc.NewServer() // Create a new RPC server
s.RegisterCodec(json.NewCodec(), "application/json") // Register the type of data requested as JSON
s.RegisterService(new(JSONServer), "") // Register the service by creating a new JSON server
r := mux.NewRouter()
r.Handle("/rpc", s)
log.Fatal(http.ListenAndServe(port, r))
}
Things to note:
- we've had to rename the standard
encoding/json
tojsonparse
to avoid clashing with thegorilla/rpc
json library in our code. - we're using a gorilla mux
- we are registering a codec for application/json
- we register the service
- in the service we're
unmarshaling
a file into an array - our results are sent back in JSON format.
So, how do we run this? Where is the client application this time? Of course we could create one but we can just as easily demo it with a fairly simple curl request.
curl -X POST \
http://localhost:8080/rpc \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"method": "JSONServer.GiveRepoDetails",
"params": [{
"name": "go-me"
}],"id": "1"}'
Things to note about the curl
request:
- To get a response you need an ID, I too learned this the hard way after way too much time thinking where is my response? Why is there no output? Thanks to this post on SO I resolved my issue by adding the
"id": "1"
section.
I hope this has been simple enough for you get an easy takeaway from, about why and how you might use the gorilla
libs to help you knock up an RPC json solution.
Best wishes.
34