httpgrpc

package module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 13, 2021 License: MIT Imports: 6 Imported by: 0

README

httpgrpc

GoDoc Build Status GitHub tag (latest SemVer) Coverage Status Go Report Card Maintainability GitHub

Golang API and Client to standardise conversion of HTTP requests to Google Remote Procedure Calls (GRPC). Allows a generic web proxy to talk to GRPC services via a standard message while still allowing each service to maintain its API using GRPC and protocol buffers.

There are multiple implemenations that follow this basic intent already (HTTP+JSON reverse proxied to GRPC) but assume each service is directly handling external HTTP traffic, rather than sitting behind load-balanced webservers in a DMZ somewhere separate to your nice safe application servers. For example, here and here.

This differs, in that your GRPC services are only expected to be handling GRPC. The logic used by the reverse proxy to determine where to send the message is up to you, this library does not cover service discovery or decoding the URL to extract data such as procedure or service names.

In order to expose a method to HTTP, the protobuf should define a service in which each method is prefixed by an HTTP method. The service application must then implement a version of that method without the method name. The easiest way to do this is to specify two service definitions, one with only exposed method matching the internal method, as below:

service App {
    rpc ListThings (ListThingsRequest) returns (ListThingsResponse) {}
    rpc RemoveThing (ThingID) returns (Thing) {}
    rpc AddThing (Thing) returns (ThingID) {}
}

service ExposedApp {
    rpc GetListThings (ListThingsRequest) returns (ListThingsResponse) {}
}

In this example, App would provide three GRPC endpoints, but only one would be exposed for HTTP methods from the proxy. Important to note is that you don't need to actually implement GetListThings in this example, simply defining it will allow httpgrpc to lookup the ListThings method on your real server.

Installation

go get "github.com/LLKennedy/httpgrpc"

Basic Usage

In Your Web Proxy
import "github.com/LLKennedy/httpgrpc"

...

func (ws *WebServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // Handle other endpoints before this, ProxyRequest will always write to w
    // Your URL decoding and service discovery goes here, filling the two variables below.
    var procedure string
    var clientConn *grpc.ClientConn
    // Optionally you can also provide a transaction ID, a unique string that identifies this request. Empty string can be provided.
    var string txid
    // This will automatically convert the request into a proxy message and send it to the client, which is assumed to implement httpgrpc/proto.ExposedServiceServer
    // After converting and sending the message, it will parsse the response and write to w
    return httpgrpc.ProxyRequest(context.Background(), w, r, procedure, clientConn, txid)
}
In Your Application Service
import "github.com/LLKennedy/httpgrpc"

...

// Handle is an example GRPC server for a microservice matching the example App protobuf from earlier - actual GRPC methods not defined in this example.
type Handle struct {
    server *grpc.Server
    proxy  interface{ Serve(net.Listener) error }
    photos map[string][]byte
}

// New creates a new server
func New() (*Handle, error) {
    s := new(Handle)
    s.server = grpc.NewServer()
    var err error
    // This is the magic bit - &UnimplementedExposed<Service>Server{} defines the API, then we pass it the handler (s) and a GRPC server.
    // The GRPC server can be the same one your app server is using, or a different one if you want to run the exposed endpoints on a different port or with different TLS settings.
    s.proxy, err = httpgrpc.NewServer(&UnimplementedExposedAppServer{}, s, s.server)
    if err != nil {
        return nil, err
    }
    RegisterAppServer(s.server, s)
    return s, nil
}

// Start starts the server
func (h *Handle) Start() error {
    listener, err := net.Listen("tcp", ":8953")
    if err != nil {
        return err
    }
    go func() {
        h.proxy.Serve(listener)
    }()
    return h.server.Serve(listener)
}

Testing

On windows, the simplest way to test is to use the powershell script.

./test.ps1

To emulate the testing which occurs in build pipelines for linux and mac, run the following:

go test ./... -race

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewServer added in v0.2.0

func NewServer(api, server interface{}, listener *grpc.Server, bypassInterceptors bool) (*proxy.Server, error)

NewServer creates a new server to convert httpgrpc/proto messages to service-specific messages

func ProxyRequest added in v0.2.0

func ProxyRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, procedure string, conn *grpc.ClientConn, txid string, loggers ...logs.Writer)

ProxyRequest proxies an HTTP request through a GRPC connection compliant with httpgrpc/proto

Types

This section is empty.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL