Skip to content

pablolagos/go-jsonrpc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Version License Issues Code Size Last Commit Go Report Card

Stars Stars Forks Documentation

Go JSON-RPC

A versatile and lightweight JSON-RPC 2.0 server implementation in Go, designed to handle JSON-RPC requests over TCP, Unix sockets, CGI, and HTTP. It provides a full set of helper functions to register commands, handle middlewares, and work with JSON-RPC data in a flexible and customizable way.

Features

  • Multiple transport protocols: TCP, Unix sockets, CGI, and HTTP.
  • Middleware support: Easily add global or command-specific middlewares.
  • Helper functions: Simplify request handling, parameter retrieval, and response management.
  • Flexible configuration: Customize logging, error handling, and server options.

Installation

To install this package, use:

go get github.com/pablolagos/go-jsonrpc

Usage

Basic Server Setup (TCP and Unix Sockets)

1. TCP Server Example

package main

import (
    "errors"
    "log"
    "os"
    "github.com/pablolagos/go-jsonrpc"
)

func main() {
    options := &go_jsonrpc.Options{
        CGI:    false,
        Logger: log.New(os.Stdout, "JSON-RPC TCP Server: ", log.LstdFlags),
    }

    jsrpc := go_jsonrpc.New(options)

    // Register a command
    jsrpc.RegisterCommand("add", func(ctx *go_jsonrpc.Context) error {
        a := ctx.GetParamFloat("a", 0.0)
        b := ctx.GetParamFloat("b", 0.0)
        result := a + b
        return ctx.JSON(result)
    })

    // Start the server on a TCP port
    address := ":12345"
    log.Printf("Starting server on %s\n", address)
    if err := jsrpc.StartServer(address, false); err != nil {
        log.Fatalf("Failed to start server: %v\n", err)
    }
}

2. Unix Socket Example

package main

import (
    "errors"
    "log"
    "os"
    "github.com/pablolagos/go-jsonrpc"
)

func main() {
    options := &go_jsonrpc.Options{
        CGI:    false,
        Logger: log.New(os.Stdout, "JSON-RPC Unix Socket Server: ", log.LstdFlags),
    }

    jsrpc := go_jsonrpc.New(options)

    jsrpc.UseGlobalMiddleware(func(ctx *go_jsonrpc.Context) error {
        authToken := ctx.GetParamString("authToken", "")
        if authToken != "secret" {
            return errors.New("unauthorized access")
        }
        return nil
    })

    jsrpc.RegisterCommand("multiply", func(ctx *go_jsonrpc.Context) error {
        a := ctx.GetParamFloat("a", 1.0)
        b := ctx.GetParamFloat("b", 1.0)
        result := a * b
        ctx.JSON(result)
        return nil
    })

    socketPath := "/tmp/jsonrpc.sock"
    if _, err := os.Stat(socketPath); err == nil {
        os.Remove(socketPath)
    }

    log.Printf("Starting server on Unix socket %s\n", socketPath)
    if err := jsrpc.StartServer(socketPath, true); err != nil {
        log.Fatalf("Failed to start server: %v\n", err)
    }
}

CGI Example

When running in a CGI environment, the library can automatically handle JSON-RPC requests by reading from os.Stdin and writing responses to os.Stdout.

package main

import (
    "log"
    "os"
    "github.com/pablolagos/go-jsonrpc"
)

func main() {
    options := &go_jsonrpc.Options{
        CGI:    true, // Enables CGI headers
        Logger: log.New(os.Stdout, "JSON-RPC CGI Server: ", log.LstdFlags),
    }

    jsrpc := go_jsonrpc.New(options)

    jsrpc.RegisterCommand("subtract", func(ctx *go_jsonrpc.Context) error {
        a := ctx.GetParamFloat("a", 0.0)
        b := ctx.GetParamFloat("b", 0.0)
        result := a - b
        return ctx.JSON(result)
    })

    if err := jsrpc.ExecuteCommand(os.Stdin, os.Stdout); err != nil {
        log.Fatalf("Error processing CGI request: %v", err)
    }
}

HTTP Server Example

To run the server over HTTP, use Go's net/http package alongside the JSON-RPC library.

package main

import (
    "log"
    "net/http"
    "github.com/pablolagos/go-jsonrpc"
)

func main() {
    options := &go_jsonrpc.Options{
        CGI:    false,
        Logger: log.New(os.Stdout, "JSON-RPC HTTP Server: ", log.LstdFlags),
    }

    jsrpc := go_jsonrpc.New(options)

    jsrpc.RegisterCommand("divide", func(ctx *go_jsonrpc.Context) error {
        a := ctx.GetParamFloat("a", 1.0)
        b := ctx.GetParamFloat("b", 1.0)
        if b == 0 {
            return ctx.ErrorString(400,"division by zero")
        }
        result := a / b
        return ctx.JSON(result)
    })

    http.HandleFunc("/rpc", func(w http.ResponseWriter, r *http.Request) {
        jsrpc.ExecuteCommand(r.Body, w)
    })

    log.Println("Starting HTTP server on :8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatalf("Failed to start HTTP server: %v", err)
    }
}

Middleware Example

Middlewares can be applied globally or specifically for individual commands. Note: If a middleware encounters an error, it is responsible for handling client responses as needed.

package main

import (
    "errors"
    "log"
    "os"
    "github.com/pablolagos/go-jsonrpc"
)

func main() {
    options := &go_jsonrpc.Options{
        Logger: log.New(os.Stdout, "JSON-RPC Server with Middleware: ", log.LstdFlags),
    }

    jsrpc := go_jsonrpc.New(options)

    jsrpc.UseGlobalMiddleware(func(ctx *go_jsonrpc.Context) error {
        token := ctx.GetParamString("token", "")
        if token != "valid_token" {
            ctx.ErrorString(412, "unauthorized access")
            return errors.New("unauthorized access") // Return an error to stop command execution
        }
        return nil
    })

    jsrpc.RegisterCommand("echo", func(ctx *go_jsonrpc.Context) error {
        message := ctx.GetParamString("message", "")
        return ctx.JSON(message)
    })

    address := ":12345"
    log.Printf("Starting server on %s\n", address)
    if err := jsrpc.StartServer(address, false); err != nil {
        log.Fatalf("Failed to start server: %v\n", err)
    }
}

Handler interceptors

See Interceptor for more details on how to use handler interceptors to modify request handling, validate requests, or force responses.

HTTPS Client Example

package main

import (
	"fmt"
	"time"

	"github.com/pablolagos/go-jsonrpc/jclient"
)

func main() {
	client := jclient.NewHTTPClient("https://localhost:8443/api", jclient.HTTPClientOptions{Insecure: false, Timeout: 15 * time.Second}) // true = skip TLS verify

	var result map[string]interface{}
	err := client.Call("ping", map[string]string{"msg": "hello"}, &result)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("Response:", result)
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

go-jsonrpc is a package to create json-rpc on CGI, HTTP or Unix Sockets in Go

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published