GithubHelp home page GithubHelp logo

reddec / rpc Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 1.0 41 KB

Golang and JS interaction made simple

License: MIT License

Makefile 0.48% JavaScript 1.21% Go 97.74% HTML 0.56%
rpc golang-json-api golang-rpc

rpc's Introduction

RPC

Go Reference

Calling Golang backend should be simple.

  • no runtime dependencies (for TS generator there is a compile-time dependency)
  • 100% test coverage
  • simple and efficient

This project was created within one night after my frustration while writing yet another service which basically exposes DB operations as an HTTP endpoint. The problem is that most of the current approaches offer some kind of framework lock. Once you write your business logic, you will, basically, have to duplicate the method, which will just accept values from an HTTP request and proxy it to the business function.

This project allows you to expose almost any kind of structure method as HTTP endpoints.

Supports:

  • Any input and output arguments as soon as it is supported by JSON encoder/decoder
    • (optionally) First argument can be context.Context and it will be wired to request.Context()
  • Value and/or error output. Example:
    • Foo(...)
    • Foo(...) error
    • Foo(...) int64
    • Foo(...) (int64, error)

There are two main packages: rpc and jrpc. The rpc is array-based interaction (function arguments are mapped as-is as array), and jrpc package is single-payload oriented.

rpc provides less restrictions for Go side, while jrpc more friendly for UI and code-generators.

Simplest possible example:

package main

type Service struct{}

func (srv *Service) Sum(a, b int64) int64 {
	return a + b
}

func main() {
	http.Handle("/api/", http.StripPrefix("/api", rpc.New(&Service{})))
	http.ListenAndServe("127.0.0.1:8080", nil)
}

In JS side (you can just copy-and-paste)

function RPC(baseURL = "") {
    return new Proxy({}, {
        get(obj, method) {
            method = method.toLowerCase();
            if (method in obj) {
                return obj[method]
            }

            const url = baseURL + "/" + encodeURIComponent(method)
            const fn = async function () {
                const args = Array.prototype.slice.call(arguments);
                const res = await fetch(url, {
                    method: "POST",
                    body: JSON.stringify(args),
                    headers: {
                        "Content-Type": "application/json"
                    }
                })
                if (!res.ok) {
                    const errMessage = await res.text();
                    throw new Error(errMessage);
                }
                return await res.json()
            }
            return obj[method] = fn
        }
    })
}

And use it as:

const api = RPC("/api");

const amount = await api.sum(123, 456)

Alternative is to use CDN (seriously? for 375 bytes?)

<script type="module">
    import RPC from "https://cdn.jsdelivr.net/gh/reddec/rpc@1/js/rpc.min.js"

    const API = RPC("/api");
    const total = await API.sum(123, 456);
</script>

Dynamic session

In some cases you may need to prepare session, based on request: find user, authenticate it and so on. For that use Builder.

Builder will invoke factory on each request and use returned value as API session object.

For example:

package main

import (
	"net/http"
	"github.com/reddec/rpc"
)

type userSession struct {
	user string
}

func (us *userSession) Greet() string { // this will be an exported method
	return "Hello, " + us.user + "!"
}

type server struct{}

func (srv *server) newSession(r *http.Request) (*userSession, error) {
	user := r.Header.Get("X-User") // mimic real authorization
	return &userSession{
		user: user,
	}, nil
}

func main() {
	var srv server // initialize it!
	http.Handle("/api/", http.StripPrefix("/api", rpc.Builder(srv.newSession)))
	http.ListenAndServe("127.0.0.1:8080", nil)
}

Now, on call api.greet(), first will be executed newSession and then userSession.Greet

Supporting tools

RPC script

Minified version of js/rpc.js supporting script (~400B) embedded to the library and available as global variable rpc.JS and can be exposed as handler by Script function:

// ...
http.Handle("/static/js/rpc.min.js", rpc.Script())

Schema

Package schema provides simple way to generate OpenAPI 3.1 schema based on indexed methods from server. The generated object could be serialized as YAML or JSON and served as handler.

The function schema.OpenAPI uses result of Index function to generate schema and definition.

var srv Server
index := rpc.Index(&srv)
schema := schema.OpenAPI(index) // customizable by Options
// render as JSON or YAML

For the convenience use handler to export schema over HTTP. It will pre-generate and cache schema.

var srv Server
index := rpc.Index(&srv)
// ...
http.Handle("/schema", schema.Handler(index))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.