Updates every backend dependency with a newer release available, and tidies the example module alongside as any change to backend/go.mod requires.
6.5 KiB
jrpc - rpc with json

jrpc library provides client and server for RPC-like communication over HTTP with json encoded messages.
The protocol is a somewhat simplified version of json-rpc with a single POST call sending Request json
(method name and the list of parameters) moreover, receiving json Response with result data and an error string.
Usage
Plugin (server)
// Plugin wraps jrpc.Server and adds synced map to store data
type Plugin struct {
*jrpc.Server
}
// create plugin (jrpc server) with NewServer where required param is a base url for rpc calls
plugin := jrpc.NewServer("/command")
// then add your function to map
plugin.Add("mycommand", func(id uint64, params json.RawMessage) jrpc.Response {
return jrpc.EncodeResponse(id, "hello, it works", nil)
})
// and run server with port number value
plugin.Run(8080)
The constructor NewServer accepts two parameters:
API- a base url for rpc callsOptions- optional parameters such as timeouts, logger, limits, middlewares and so on.Auth- sets basic auth credentials, acceptsusernameandpassword. Auth is enforced only if both of them set to non-empty values; setting just one leaves the server serving every request unauthenticatedWithTimeouts- sets server timeouts, accepts aTimeoutsstruct withReadHeaderTimeout,WriteTimeout,IdleTimeoutandCallTimeout.CallTimeoutlimits the time allowed for a single call and responds with503if exceeded, and has to be set belowWriteTimeout, otherwise the write deadline kills the connection before the503can be sentWithLimits- defines a limit of calls/sec per client, accepts limit value infloat64typeWithThrottler- sets throttler middleware limiting the number of parallel calls to the serverWithSignature- sets server signature, accepts appName, author and version. Disabled by defaultWithLogger- defines custom logger (e.g. lgr)WithMiddlewares- sets custom middlewares list to server, accepts list of handlers with idiomatic typefunc(http.Handler) http.Handler
Example with options:
import (
"time"
"github.com/go-pkgz/jrpc"
"github.com/go-pkgz/rest"
)
plugin := jrpc.NewServer("/command",
jrpc.Auth("user", "password"),
jrpc.WithTimeouts(jrpc.Timeouts{
ReadHeaderTimeout: 5 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 10 * time.Second,
CallTimeout: 25 * time.Second,
}),
jrpc.WithThrottler(120),
jrpc.WithLimits(100),
jrpc.WithSignature("the best plugin ever", "author", "1.0.0"),
jrpc.WithMiddlewares(rest.Trace),
)
Application (client)
// Client makes jrpc.Client and invoke remote call
rpcClient := jrpc.Client{
API: "http://127.0.0.1:8080/command",
Client: http.Client{},
AuthUser: "user",
AuthPasswd: "password",
}
resp, err := rpcClient.Call("mycommand")
var message string
if err = json.Unmarshal(*resp.Result, &message); err != nil {
panic(err)
}
Running the example
_example has a working pair of a plugin and an application.
Both are separate go modules pointing to the local jrpc with a replace directive, so no extra setup is needed
beyond go 1.24 or later and a free local port 8080. Start the plugin first, in one terminal:
cd _example/plugin
go run .
It registers two handlers and listens on port 8080:
[INFO] add handler for store.save
[INFO] add handler for store.load
[INFO] listen on [::]:8080
Then run the application in another terminal:
cd _example/application
go run .
It calls the plugin three times and prints the results:
stored {TS:2025-01-12 12:00:00 +0000 UTC Value:12345} with id=54118548792
loaded {TS:2025-01-12 12:00:00 +0000 UTC Value:12345} from id=54118548792
can't load for id=something, not found
The application exits on its own, the plugin keeps listening until stopped with Ctrl-C.
Technical details
jrpc.Serverruns on user-defined port as a regular http server- Server accepts a single POST request on user-defined url with Request sent as json payload
request details and an example:
```go
type Request struct {
Method string `json:"method"`
Params interface{} `json:"params,omitempty"`
ID uint64 `json:"id"`
}
```
example:
```json
{
"method":"test",
"params":[123,"abc"],
"id":1
}
```
- Params can be a struct, primitive type or slice of values, even with different types.
- Server defines
ServerFnhandler function to react on a POST request. The handler provided by the user. - Communication between the server and the caller can be protected with basic auth. The protection is on only if
both user and password set with the
Authoption; with either of them empty the server responds to every request without asking for credentials. - Client provides a single method
Calland returnResponse
response details:
// Response encloses result and error received from remote server
type Response struct {
Result *json.RawMessage `json:"result,omitempty"`
Error string `json:"error,omitempty"`
ID uint64 `json:"id"`
}
- User should encode and decode json payloads on the application level, see provided examples
jrpc.Serverdoesn't support https internally (yet). If used on exposed or non-private networks, should be proxied with something providing https termination (nginx and others).
Status
The code was extracted from remark42 and still under development. Until v1.x released the API & protocol may change.