DEV Community

elesq
elesq

Posted on

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...

Jason not 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.

Setup the project

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
Enter fullscreen mode Exit fullscreen mode

go get github.com/gorilla/rpc
go get -u github.com/gorilla/mux

The json data file

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"
    }
]
Enter fullscreen mode Exit fullscreen mode

You can adapt your file, structures to suit your case or just to play around with more complex structures.

Implementing the RPC server

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))

}
Enter fullscreen mode Exit fullscreen mode

Things to note:

  • we've had to rename the standard encoding/json to jsonparse to avoid clashing with the gorilla/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.

Testing our server

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"}'
Enter fullscreen mode Exit fullscreen mode

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.

victory

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.

Top comments (8)

Collapse
 
akhror_mamasoliev_eb15e5f profile image
Akhror Mamasoliev

Hi ! how can I get error respone like this
Error {
ErrorCode int
ErrorMsg string
}

Now I get Error in string

Collapse
 
kamrana62744634 profile image
Kamran Ali

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 j son solution.
thevloggingtech.com/

Collapse
 
uzi0909 profile image
uzi0909 • Edited

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 j son solution.
texthubb.com/

Collapse
 
zainakbar786 profile image
zAin...........!

I hope this was clear enough for you to understand why and how you could utilise the gorilla libs to assist you in creating an RPC j son solution.
picsapkstudio.com/

Collapse
 
uzi0909 profile image
uzi0909

I hope this was clear enough for you to understand why and how you could utilise the gorilla libs to assist you in creating an RPC j son solution.

Collapse
 
mediocrepipe profile image
mediocrepipe

Thank You Loker Berau

Collapse
 
badar909 profile image
Klinsmann K187

I am very grateful for this help
Regards: Klinsmann K187

Collapse
 
zain909 profile image
zain909

Thank you so much it was very helpful for me to solving my issue