A reduced, refined gRPC implementation in Go

Overview

reRPC

Build Report Card GoDoc

reRPC is a small framework for building HTTP APIs. You write a short API definition file and implement your application logic, and reRPC generates code to handle marshaling, routing, error handling, and content-type negotiation. It also generates an idiomatic, type-safe client.

reRPC is wire-compatible with both the gRPC and Twirp protocols, including full support for gRPC streaming. reRPC servers interoperate seamlessly with generated clients in more than a dozen languages, command-line tools like grpcurl, and proxies like Envoy and gRPC-Gateway. Thanks to Twirp's simple, human-readable JSON protocol, reRPC servers are also easy to debug with cURL.

Under the hood, reRPC is just protocol buffers and the standard library: no custom HTTP implementation, no new name resolution or load balancing APIs, and no surprises. Everything you already know about net/http still applies, and any package that works with an http.Server, http.Client, or http.Handler also works with reRPC.

For more on reRPC, including a walkthrough and a comparison to alternatives, see the docs.

A Small Example

Curious what all this looks like in practice? Here's a small h2c server:

package main

import (
  "net/http"

  "golang.org/x/net/http2"
  "golang.org/x/net/http2/h2c"

  pingpb "github.com/rerpc/rerpc/internal/ping/v1test" // generated
)

type PingServer struct {
  pingpb.UnimplementedPingServiceReRPC // returns errors from all methods
}

func main() {
  ping := &PingServer{}
  mux := rerpc.NewServeMux(
    pingpb.NewPingHandlerReRPC(ping),
    rerpc.NewBadRouteHandler(),
  )
  handler := h2c.NewHandler(mux, &http2.Server{})
  http.ListenAndServe(":8081", handler)
}

With that server running, you can make requests with any gRPC client or with cURL:

$ curl --request POST \
  --header "Content-Type: application/json" \
  http://localhost:8081/internal.ping.v1test.PingService/Ping

{"code":"unimplemented","msg":"internal.ping.v1test.PingService.Ping isn't implemented"}

You can find production-ready examples of servers and clients in the API documentation.

Status

This is the earliest of early alphas: APIs will break before the first stable release.

Support and Versioning

reRPC supports:

Within those parameters, reRPC follows semantic versioning.

Legal

Offered under the MIT license. This is a personal project developed in my spare time - it's not endorsed by, supported by, or (as far as I know) used by my current or former employers.

Issues
  • Unify Request and Response into Message

    Unify Request and Response into Message

    Originally, we expected the generic Request and Response types to diverge quite a bit. In practice, they've ended up nearly identical. The methods we anticipate adding (primarily DisableCompression()) apply equally to both.

    The code for the two types is so similar that we're often making near-identical changes to their code. (For example, supporting trailers required verbatim copies across the two types.)

    This commit unifies the two types into connect.Message. We can then unify AnyRequest/AnyResponse and ReceiveRequest/ReceiveResponse. Since Request.Msg was never @bufdev's favorite and Message.Msg is even worse, I've renamed to Message.Body - but I'm totally open to suggestions for a better field name.

    After this PR, we've slimmed down connect's exported API quite a bit. On my monitor, the GoDoc table of contents now fits (barely) on one screen.

    opened by akshayjshah 17
  • Implement gRPC's standard interop tests

    Implement gRPC's standard interop tests

    The first-party gRPC implementations have a standardized battery of interoperability tests. Many of them test particular flags or option schemes that may not apply to us, but let's see if we can get some useful test coverage from them.

    https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md

    enhancement 
    opened by akshayjshah 12
  • Random Compression Method Selection

    Random Compression Method Selection

    Say you register 4 compression methods on both the handler and the client.

    It seems like the server picks the first compression method it recognizes, unless a specific method was used when sending the request.

    However, looking at the client side the order the methods are sent is random since it collects names from a map.

    As far as I can tell this makes it impossible to select an order of preference from the client side. Furthermore it appears to me that gzip cannot be removed from the pool, only replaced.

    enhancement 
    opened by klauspost 11
  • More request information in Interceptor.WrapStreamContext()

    More request information in Interceptor.WrapStreamContext()

    Currently there is no way to enrich a stream context with information about the request. The WrapStreamContext() method only accepts a parent context and does not give us any information about the request.

    In particular, we need access to the endpoint spec and request headers.

    Our primary use case for this is authentication, where we would like to be able to apply some generic token parsing and validation logic to all requests, and enrich context with authentication info.

    enhancement 
    opened by anzboi 10
  • Rename protoc-gen-go-connect to protoc-gen-goconnect/protoc-gen-connectgo?

    Rename protoc-gen-go-connect to protoc-gen-goconnect/protoc-gen-connectgo?

    The go-.* paradigm is really only used by protoc-gen-go-grpc, which is relatively new, and I'd argue that it's not productive. We generally want people to get into the habit of generating to a sub-directory named after their plugin, So we might want to have i.e /internal/gen/proto/goconnect or internal/gen/proto/connectgo, and then name the plugin accordingly.

    Note that we did the same go-.* style with our internal plugins for bufbuild/buf (this is on me), so we should probably change that too once we agree on the naming scheme.

    opened by bufdev 8
  • Support dynamic input type and output type

    Support dynamic input type and output type

    Is your feature request related to a problem? Please describe.

    Trying to build a connect gateway, support post and grpc.

    The proto is dynamic, generated from grpc reflect, but connect handler can not use the dynamic type due to handler code like this

    request = &Request[Req]{
      Msg:    new(Req),
      spec:   receiver.Spec(),
      header: receiver.Header(),
    }
    

    I think connect-go can support dynamic pb type, the input and output type is based on reflect MessageType, maybe pass from HandlerOption, so NewUnaryHandler[any,any]() can work as expected.

    Describe the solution you'd like

    Describe alternatives you've considered

    Additional context

    connect protocol makes grpc eaiser, but for migration, need a gateway to translate the protocol for other languages that don't speak connect protocol.

    enhancement 
    opened by wenerme 6
  • Fixed README examples; Set autogeneration of them using mdox tool.

    Fixed README examples; Set autogeneration of them using mdox tool.

    Hey!

    Huge fan here, this project is amazing! 💪🏽 It has lots of features (3 protocols in one), so I think examples has to be clear. I found the existing ones obsolete so I recreated them and committed with tooling that autogenerates them in README once changed.

    make test also checks if the examples are buildable, which will keep them up-to-date!

    Hopefully that will help make this project more accessible, cheers. Keep the good work!

    I hope you don't mind putting auto-formatter for README. It ensures consistency and e.g puts all on single line (all IDEs handle that just fine, so no point in trying to manually adjust width of text)

    Signed-off-by: Bartlomiej Plotka [email protected]

    opened by bwplotka 6
  • Evaluate Style Guide

    Evaluate Style Guide

    Package Structure

    • [x] The codec and compress packages are split out so that we can more easily add a separate package for the Protocol abstraction (e.g. gRPC, gRPC-Web, Connect) without introducing an import cycle.
    • [x] The clientstream and handlerstream packages are split out so that we can tidy up names for these types. Otherwise, you'd have names like NewClientClientStream (the client's view of a client streaming endpoint).
    • [x] We might want it to be compress.Gzip instead of compress.GzipCompressor.
      • Edit: We'll move this to compress/gzip.Compressor.

    Method Naming

    • [x] The stream has a ReceivedHeader method to distinguish itself from the request headers. Should we instead just name this ResponseHeader for clarity?
    • [x] Similarly, let's make it explicit to be RequestHeader and ResponseHeader.
    • [x] As discussed, we need to decide what we're doing with Simple/Full.
      • Client-side: WrappedPingClient and UnwrappedPingClient interfaces. PingClient is reserved for the type that users interact with.
      • Server-side: PingService (acts upon generic types), and NewPingService (acts upon any). Comments are left in-line to describe how to implement the simple, non-generic method signatures.

    Future Proofing

    • [x] Top-level abstractions (e.g. Codec and Compressor) are propagated through the clientCfg and into the protocol abstraction via a catch-all protocolClientParams. If we eventually plan to export the protocol abstraction and include it as a ClientOption, the relationship here is fuzzy.
      • What happens if we ever have a protocol that doesn't interact with all of the protocolClientParams types - is it a no-op, an error, or a silent failure?
      • We could tie these options to each protocol individually to clear these relationships up, but we end up with some more repetition (i.e. we need to repeat the same options for similar protocols like gRPC and gRPC-Web). For example, each of the gRPC and gRPC-Web protocols would have a Codec option.
      • In the connect-api branch, we were able to get around this because the protocols were separate client implementations, and they could each individually own what options they exposed (e.g. here).
    • [x] We still need to figure out error details. I know the gRPC protocol requires the proto.Any, and Akshay had some ideas around this - we could rename the methods to include Any so it leaves room for us to add other types later (e.g. AddAnyDetail). The abstraction violation between the pluggable Codec and the proto.Any sucks, but I know we're at mercy to the gRPC protocol here.

    1.0 Features

    • [x] The gRPC health and reflection packages are valuable, but they aren't really necessary to begin with. We should consider whether or not these packages should exist in a separate repository (similar to gRPC middleware repositories).
      • I know we need to be mindful of this w.r.t. including the RegistrationName in the generated code. If we were to drop this support to begin with, we'd need to reintroduce this as a HandlerOption later, and that's tied to the connect library itself. It's not immediately obvious how this would work.
      • Decision: health and reflection are staying where they are. We need these features for easy gRPC user adoption. To be clear, health is non-optional. reflection is a huge quality of life improvement and its (nearly) part of the gRPC specification at this point.
    • [x] connect.MaxHeaderBytes is kinda nice, but doesn't feel necessary and is prone to change across different protocols.
    • [x] Should connect.ReceiveResponse be in an internal package? It's only used twice and otherwise distracts from the API that users ought to interact with. This might already be your plan based on the conversations we had earlier about the user-facing API and connect internals.
      • It looks like ReceiveRequest needs to be exported for the generated code, so I can see an argument to export it for symmetry.
    • [x] Drop IsValidHeaderKey and IsValidHeaderValue.

    Implementation Details

    • [x] In the connect-api branch, I left a note for myself about whether or not the discard helper function can hang forever (e.g. discard(cs.response.Body)). This might have happened when I introduced the gRPC testing suite, but I can't recall. We need to make sure this can't happen.
      • Nothing to do here - this is a consequence of needing to read the http.Response.Body to completion to reuse the connection. This is also just an implementation detail, so it's not blocking regardless.
    opened by amckinney 6
  • Support trailers?

    Support trailers?

    Should we add support for user-written trailers? We should investigate what people are doing with grpc-go's trailer APIs before we dismiss this out of hand.

    opened by akshayjshah 6
  • Add call options to extract metadata

    Add call options to extract metadata

    Currently, the metadata (headers & footers) for client requests is only visible in interceptors. We should add CallOptions that make it easier to surface these to users. The API would likely be similar to grpc.Header and grpc.Footer.

    enhancement 
    opened by akshayjshah 6
  • Add benchmarks

    Add benchmarks

    We should add a handful of benchmarks to the test suite (perhaps in the cross-tests so we can compare to grpc-go?). We should also do some local testing for more detailed throughput and latency measurement - fortio might be a good tool.

    enhancement 
    opened by akshayjshah 6
  • Add Studio and connect-web to README

    Add Studio and connect-web to README

    Add links to Studio and connect-web to the ecosystem section of the README.

    Before submitting your PR: Please read through the contribution guide at https://github.com/bufbuild/connect-go/blob/main/.github/CONTRIBUTING.md

    opened by akshayjshah 0
  • add HTTP error helper

    add HTTP error helper

    The mapping from connect error codes to HTTP status codes is currently private and not accessible to users who are implementing connect in their existing HTTP servers. This helper has been added to allow those users to easily update existing HTTP middlewares to handle connect errors.

    fixes #331

    opened by rhbuf 1
  • Compatibility layer to work with existing gRPC code

    Compatibility layer to work with existing gRPC code

    gRPC has been around for quite a while now. Lots of organizations have lots of existing code using the client stubs and server interfaces generated by protoc-gen-go-grpc (or its predecessor, the earlier version protoc-gen-go).

    This request is for a compatibility layer, that would allow gRPC client stubs to be wired up to a Connect client and gRPC server implementations to be wired up to a Connect server. This would allow an organization to migrate to Connect without having to re-write much of their codebase to refer to new types and interfaces.

    This basically boils down to adapting grpc.ClientConnInterface and grpc.ServiceRegistrar to Connect's APIs. Looking at the split of generated code vs. library code with connect, and how generics are used in the library code, it looks like this might require additional generated code. (Though this could possibly be minimized with some additions to both existing generated and library code -- like introduction of a layer that is more generic and transport-agnostic?)

    Such a compatibility layer would likely need to be in its own Go module (maybe separate repo?) so as not to pull the gRPC runtime packages into Connect's dependencies.

    enhancement 
    opened by jhump 0
  • Provide function to write RPC errors from HTTP middleware

    Provide function to write RPC errors from HTTP middleware

    Is your feature request related to a problem? Please describe. Even though Connect handlers work with net/http middleware, it's often necessary to re-implement existing HTTP middleware as Connect interceptors so that clients get nicely-annotated errors. This is a little silly.

    Describe the solution you'd like It'd be nice for Connect to include a function that HTTP middleware can use to encode Connect errors. func WriteError(http.ResponseWriter, *http.Request, error) might work.

    Describe alternatives you've considered The status quo is okay, but forces users to jump through more hoops that we'd like.

    enhancement 
    opened by akshayjshah 1
  • SendMaxBytes config option

    SendMaxBytes config option

    In https://github.com/bufbuild/connect-go/pull/311, a ReadMaxBytes option was added, but to go along with that, when you control both the client and server, an equivalent SendMaxBytes (mostly relevant for the client) to pair with ReadMaxBytes would be nice and prevent sending anything over the wire.

    In our case, we configure ReadMaxBytes on the server, and would like to pair this also on our client so if a user attempts to send a message that is too large (and would ultimately be rejected by the server anyways), we can bail early on the client before doing any extra work.

    This coincides with the gRPC MaxCallSendMsgSize option.

    enhancement 
    opened by mattrobenolt 0
  • HTTP middleware can't distinguish valid URLs from invalid

    HTTP middleware can't distinguish valid URLs from invalid

    When using net/http middleware to wrap handlers and collect logs or metrics, it's nice to be able to parse out the protobuf package name, service name, and procedure name. However, it's potentially expensive to do this without an allowlist of known RPC endpoints: any script kiddie can generate zillions of invalid URLs, which may put a lot of load on observability systems (especially systems that treat each unique combination of tags as a timeseries).

    @mattrobenolt brought this to our attention. Previously, he used grpc-go's generated ServiceDesc to build an allowlist. (This isn't what the gRPC folks want users to do with ServiceDesc, but that's beside the point.)

    Today, users have a few options to solve this problem:

    • Emit logs & metrics from a connect interceptor. At that point, URLs have already been validated and Spec.Procedure is available. However, users may end up with one log line from HTTP middleware and another from a connect interceptor.
    • Use the generated service name constants to build a partial allowlist. This only validates the package.service portion of the URL, but that's likely enough to protect from most scanning attempts.
    • Write a separate plugin to generate an exact allowlist. This works, but is a bit of a pain.

    If this is a common pain point, we could make this a bit easier by generating more code.

    enhancement 
    opened by akshayjshah 1
Releases(v0.3.0)
  • v0.3.0(Aug 1, 2022)

    What's Changed

    Breaking Changes

    • Send binary data with error details by @akshayjshah in https://github.com/bufbuild/connect-go/pull/329
      So that proxies can translate between the Connect and gRPC protocols without a schema, we've changed the Connect protocol to include base64-encoded binary data with error details. Any code sending error details must now create details with connect.NewErrorDetail instead of anypb.New. For code unmarshaling error details, the connect.ErrorDetail type has changed from an interface to a struct with a more-ergonomic Value() method.

    Note that we will not make breaking changes in minor releases after connect-go reaches v1.0. We anticipate a stable release around October of 2022, shortly after Go 1.19 is released.

    Full Changelog: https://github.com/bufbuild/connect-go/compare/v0.2.0...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jul 18, 2022)

    What's Changed

    Breaking Changes

    • Rework streaming interceptors by @akshayjshah in https://github.com/bufbuild/connect-go/pull/316.
      To better accommodate a variety of common use cases, this release changes the interface for streaming interceptors. The new interface makes simple interceptors (like header-based authentication) easier to write, and it allows streaming handlers to recover from panics with well-formed gRPC or Connect errors. Only users with custom streaming interceptors are affected - unary interceptors are unchanged.

    Note that we will not make breaking changes in minor releases after connect-go reaches v1.0. We anticipate a stable release around October of 2022, shortly after Go 1.19 is released.

    Enhancements

    • Add ReadMaxBytes option by @pkwarren in https://github.com/bufbuild/connect-go/pull/311
    • Add a panic-recovering interceptor by @akshayjshah in https://github.com/bufbuild/connect-go/pull/320

    Bugfixes

    • Fix path separators when generating code on Windows by @bufdev in https://github.com/bufbuild/connect-go/pull/298
    • Require grpc-status trailer with gRPC protocol by @lixin9311 and @pkwarren in https://github.com/bufbuild/connect-go/pull/288
    • Dedupe compression algorithm names by @mattrobenolt in https://github.com/bufbuild/connect-go/pull/308
    • Improve support for 32-bit platforms by @pkwarren in https://github.com/bufbuild/connect-go/pull/318
    • Map HTTP/2 RST_STREAM codes back to RPC codes by @akshayjshah in https://github.com/bufbuild/connect-go/pull/321

    New Contributors

    • @mattrobenolt made their first contribution in https://github.com/bufbuild/connect-go/pull/308

    Full Changelog: https://github.com/bufbuild/connect-go/compare/v0.1.1...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Jun 6, 2022)

    What's Changed

    Enhancements

    • Improved interceptor documentation by @abhinav in https://github.com/bufbuild/connect-go/pull/246
    • Reduce binary size by @akshayjshah in https://github.com/bufbuild/connect-go/pull/253
    • Fix compression negotiation for streaming with Connect protocol by @akshayjshah in https://github.com/bufbuild/connect-go/pull/268
    • Use registration order to prioritize client Accept-Encoding by @akshayjshah in https://github.com/bufbuild/connect-go/pull/269

    Bugfixes

    • Miscellaneous documentation fixes by @mfridman and @bufdev.
    • Guard against client stream panics by @pkwarren in https://github.com/bufbuild/connect-go/pull/265
    • Expand test coverage of codes by @pkwarren in https://github.com/bufbuild/connect-go/pull/266
    • Make HTTP internals less error-prone by @pkwarren in https://github.com/bufbuild/connect-go/pull/267

    New Contributors

    • @abhinav made their first contribution in https://github.com/bufbuild/connect-go/pull/246
    • @pkwarren made their first contribution in https://github.com/bufbuild/connect-go/pull/265

    Full Changelog: https://github.com/bufbuild/connect-go/compare/v0.1.0...v0.1.1

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Jun 1, 2022)

    What's Changed

    This is the first public release of connect-go, a slim framework for building browser and gRPC-compatible HTTP APIs 🤩 See the blog post and connect.build for details and documentation.

    New Contributors

    Many engineers at @bufbuild worked on connect-go, but we're especially appreciative of @severb's contributions. He's our first external contributor! In alphabetical order, this release contains contributions by:

    • @akshayjshah
    • @amckinney
    • @bufdev
    • @buildbreaker
    • @cyinma
    • @doriable
    • @lrewega
    • @mfridman
    • @severb
    • @smaye81
    • @timostamm

    Full Changelog: https://github.com/bufbuild/connect-go/commits/v0.1.0

    Source code(tar.gz)
    Source code(zip)
Owner
reRPC
A gRPC and Twirp-compatible RPC framework
reRPC
Server and client implementation of the grpc go libraries to perform unary, client streaming, server streaming and full duplex RPCs from gRPC go introduction

Description This is an implementation of a gRPC client and server that provides route guidance from gRPC Basics: Go tutorial. It demonstrates how to u

Joram Wambugu 0 Nov 24, 2021
Raft-grpc-demo - Some example code for how to use Hashicorp's Raft implementation with gRPC

raft-grpc-example This is some example code for how to use Hashicorp's Raft impl

dougsong 1 Jan 4, 2022
A suite of gRPC debugging tools. Like Fiddler/Charles but for gRPC.

grpc-tools A suite of tools for gRPC debugging and development. Like Fiddler/Charles but for gRPC! The main tool is grpc-dump which transparently inte

Bradley Kemp 1.1k Jul 26, 2022
grpc-http1: A gRPC via HTTP/1 Enabling Library for Go

grpc-http1: A gRPC via HTTP/1 Enabling Library for Go This library enables using all the functionality of a gRPC server even if it is exposed behind a

StackRox 82 Jul 28, 2022
Go based grpc - grpc gateway micro service example

go-grpc-gateway-server This repository provides an example for go based microservice. Go micro services developed based on gRPC protobuf's and also us

Suresh Yekasiri 0 Dec 8, 2021
Simple grpc web and grpc transcoding with Envoy

gRPC Web and gRPC Transcoding with Envoy This is a simple stand-alone set of con

null 0 Dec 25, 2021
Go-grpc - This is grpc server for golang.

go-grpc This is grpc server for golang. protocのインストール brew install protoc Golang用のプラグインのインストール go install google.golang.org/protobuf/cmd/protoc-gen-go

jotaro yuza 1 Jan 2, 2022
GRPC - Creating a gRPC service from scratch

#Go gRPC services course Creating a gRPC service from scratch Command line colle

Rafael Diaz Miles 1 Jan 2, 2022
Totem - A Go library that can turn a single gRPC stream into bidirectional unary gRPC servers

Totem is a Go library that can turn a single gRPC stream into bidirectional unar

Joe Kralicky 2 Jan 10, 2022
Grpc-gateway-map-null - gRPC Gateway test using nullable values in map

Demonstrate gRPC gateway behavior with nullable values in maps Using grpc-gatewa

null 1 Jan 6, 2022
Todo-app-grpc - Go/GRPC codebase containing RealWorld examples (CRUD, auth, advanced patterns, etc)

Go/GRPC codebase containing RealWorld examples (CRUD, auth, advanced patterns, e

Sammi Aldhi Yanto 3 Jun 13, 2022
GRPC - A client-server mockup, using gRPC to expose functionality.

gRPC This is a mockup application that I built to help me visualise and understand the basic concepts of gRPC. In this exchange, the client can use a

Fergal Bittles 0 Jan 4, 2022
Benthos-input-grpc - gRPC custom benthos input

gRPC custom benthos input Create a custom benthos input that receives messages f

Marco Amador 2 May 18, 2022
Go-grpc-template - A small template for quickly bootstrapping a, developer platform independent gRPC golang application

go-grpc-template A small template for quickly bootstrapping a developer platform

null 1 Jan 20, 2022
Grpc-train - Train booking demo using gRPC

gRPC Demo: Train Booking Service Description Usage Contributing Development Tool

Fadi Asfour 0 Feb 6, 2022
This repo contains a sample app exposing a gRPC health endpoint to demo Kubernetes gRPC probes.

This repo contains a sample app exposing a health endpoint by implementing grpc_health_v1. Usecase is to demo the gRPC readiness and liveness probes introduced in Kubernetes 1.23.

Nico Meisenzahl 1 Feb 9, 2022
Go-grpc-tutorial - Simple gRPC server/client using go

Simple gRPC server/client using go Run server go run usermgmt_server/usermgmt_

Renner Poveda 0 Feb 14, 2022
The Go language implementation of gRPC. HTTP/2 based RPC

gRPC-Go The Go implementation of gRPC: A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. For more information

grpc 16.5k Aug 1, 2022
Backend implementation using go, proto3 and gRPC for a mock online store

Backend implementation using go, proto3 and gRPC for a mock online store Ricardo RICO URIBE Tasks I - Order service The current system exposes a produ

Ricardo Rico 0 Oct 10, 2021