A simple RPC framework with protobuf service definitions

Twirp Logo Build Status Go Report Card GoDoc


Twirp is a framework for service-to-service communication emphasizing simplicity and minimalism. It generates routing and serialization from API definition files and lets you focus on your application's logic instead of thinking about folderol like HTTP methods and paths and JSON.

Define your service in a Protobuf file and then Twirp autogenerates Go code with a server interface and fully functional clients. It's similar to gRPC, but without the custom HTTP server and transport implementations: it runs on the standard library's extremely-well-tested-and-high-performance net/http Server. It can run on HTTP 1.1, not just http/2, and supports JSON clients for easy integrations across languages

Twirp handles routing and serialization for you in a well-tested, standardized, thoughtful way so you don't have to. Serialization and deserialization code is error-prone and tricky, and you shouldn't be wasting your time deciding whether it should be "POST /friends/:id/new" or "POST /:id/friend" or whatever. Just get to the real work of building services!

Along the way, you get an autogenerated client and a simple, smart framework for passing error messages. Nice!

For more on the motivation behind Twirp (and a comparison to REST APIs and gRPC), the announcement blog post is a good read.

Installation

Use go get to install the Go client-and-server generator:

go get github.com/twitchtv/twirp/protoc-gen-twirp

You will also need:

Documentation

On the website: https://twitchtv.github.io/twirp/docs/intro.html

Source for this documentation is in the docs subdirectory. The website is generated from that folder using Docusaurus.

Implementations in other languages

This repo only has the official generators, which write out Go and Python (partial, see #185 and #220) code.

For other languages, there are third-party generators available:

Language Clients Servers Repository
Python3 github.com/verloop/twirpy
Java github.com/fajran/protoc-gen-twirp_java_jaxrs
Java https://github.com/devork/flit
JavaScript github.com/thechriswalker/protoc-gen-twirp_js
JavaScript github.com/Xe/twirp-codegens/cmd/protoc-gen-twirp_jsbrowser
Typescript github.com/larrymyers/protoc-gen-twirp_typescript
Ruby github.com/twitchtv/twirp-ruby
Rust github.com/cretz/prost-twirp
Scala github.com/soundcloud/twinagle
Swagger github.com/elliots/protoc-gen-twirp_swagger
PHP github.com/twirphp/twirp
Dart github.com/apptreesoftware/protoc-gen-twirp_dart
Elixir github.com/keathley/twirp-elixir

This list isn't an endorsement, it's just a convenience to help you find stuff for your language.

Support and Community

We have a channel on the Gophers slack, #twirp, which is the best place to get quick answers to your questions. You can join the Gopher slack here.

Releases

Twirp follows semantic versioning through git tags, and uses Github Releases for release notes and upgrade guides: Twirp Releases

Contributing

Check out CONTRIBUTING.md for notes on making contributions.

License

This library is licensed under the Apache 2.0 License.

Comments
  • Proposed new routing format: /package/service/method

    Proposed new routing format: /package/service/method

    I think we could improve Twirp's routing scheme. It has two problems right now: the /twirp/ prefix, and the package.service scheme (instead of package/service).

    Some people have mentioned to me that they're hesitant to use Twirp because the routes are prefixed with /twirp, which is concerning to them for several reasons:

    • Trademarks: some very large organizations don't want to take any legal risks and are concerned that "twirp" could become trademarked.
    • Feels like advertising: This was mentioned in #48: putting "twirp" in all your routes feels like it's just supposed to pump Twirp's brand.
    • Homophonous with "twerp": In some Very Serious settings (like government websites), it's not okay that "twirp" sounds like "twerp", which means something like "insignificant pest."

    We currently have the /twirp prefix to avoid colliding with gRPC's routes, which live at /package.service/method, and to reserve a space for future APIs (like a reflection server).

    Slashes-based routes (instead of dot-based) would be preferable because lots of existing technology expects slash-based routing. Load balancers and proxies use slashes for namespaces. If Twirp used a slash after the package name, users could leverage this much more easily. This is often possible with dots, just annoying, as you have to write a (possibly pretty complex) regex.

    I think we can fix both of these in one go. This would be a breaking change at the protocol level, so it's something to take very seriously, but I think we can do it without much pain. It would just take a version bump to v6.


    Proposed Implementation:

    I propose we use a new routing scheme: /<package>/<service>/<method>.

    This does not collide with gRPC's routes, which is good. I think it gives us flexibility to put future routes in by putting them under a Twirp package. We could provide a reflection service like this one, which lists available services:

    syntax = "proto3";
    
    package twirp.meta
    
    import "github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto"
    
    service Reflector {
      rpc ListServices(ListServiceRequest) returns (ListServiceResponse);
    }
    
    message ListServiceRequest {}
    message ListServiceResponse {
      repeated protobuf.ServiceDescriptorProto services = 1;
    }
    

    It would live at /twirp.meta/Reflector, which seems good to me.

    Regarding compatibility: generated clients would always use the new routing scheme. Generated servers would be able to use both, in case your users have old generated clients still around. We would accomplish this by exporting two path prefixes:

    const (
      HaberdasherPathPrefix = "/notreal.example/Haberdasher/"
      HaberdasherLegacyPathPrefix = "/twirp/notreal.example.Haberdasher/"
    )
    

    Users can mount both on a mux if they want to support old clients. If not, they can just use the new one.

    If we do this, there are other consequences.

    • Documentation would need to be updated everywhere.
    • Server implementations in other languages would need to be updated ASAP, as new clients won't work with old servers.
    • If people have log parsing or metrics gathering code that operates on routes, they'd need to change them.

    The pain of those other consequences is a good reason that we should try to get this out promptly, if we do it.

  • Spec doesn't mention CamelCasing the URL

    Spec doesn't mention CamelCasing the URL

    The way URLs are defined makes one believe the exact name of service is accepted. https://github.com/twitchtv/twirp/blob/03ac4c/docs/spec_v5.md#urls

    In practice however both service and method names are changed. https://github.com/twitchtv/twirp/blob/03ac4c/protoc-gen-twirp/generator.go#L956

    Should I add this to the spec for clarity and such that others do not get blind-sided by it while implementing?

    @khevse discovered it in twirpy I believe at least the rust, swagger, TypeScript, Dart and php implementations suffer from this.

    Aside: The method itself is marked internal API. It might be easier for implementations if it were public https://github.com/twitchtv/twirp/blob/03ac4c/internal/gen/stringutils/stringutils.go#L71

  • Proposal: Go streaming API

    Proposal: Go streaming API

    #3 lays out some ideas for how Twirp could support streaming RPCs on the wire. Equally important is how we support them in generated code.

    This issue is for designing the generated Go code. When we've landed on a proposal that seems pretty good, I'll edit this top text with what we've got, and then we can look at implementing it.

    Let's use this service to discuss what things would look like:

    syntax = "proto3";
    
    service Streamer {
      rpc Transaction(Req) returns (Resp);
      rpc Upload(stream Req) returns (Resp);
      rpc Download(Req) returns (stream Resp);
      rpc Bidirectional(stream Req) returns (stream Resp);
    }
    
    message Req {}
    message Resp {}
    
  • Proposal: Client-Side Hooks in Go

    Proposal: Client-Side Hooks in Go

    Similar to how the server-side hooks area thing, it'd be beneficial to have client-side hooks as well for automating things such as client-side logging, retries, etc.

    Here's a rough draft of the API that I've thought up.

    type ClientHooks struct {
      // RequestPrepared is called as soon as a request has been created and before it has been sent 
     // to the Twirp server.
      RequestPrepared func(context.Context, *http.Request) (context.Context, error)
    
     // RequestFinished (alternatively could be named ResponseReceived and take in some response from 
     // the server as well) is called after a request has finished sending. Since this is terminal, the context is 
     // not returned. 
     RequestFinished func(context.Context)
    
     // Error hook is called whenever an error occurs during the sending of a request. The Error is passed
     // as an argument to the hook.
      Error func(context.Context, twirp.Error) context.Context 
    }
    

    Looking forward to hearing y'alls thoughts!

  • Add support for TooManyRequests (429) error code

    Add support for TooManyRequests (429) error code

    Add support for a "TooManyRequests" Twirp error code, which will get translated to the equivalent 429 HTTP error code.

    Why call this TooManyRequests instead of RateLimitExceeded?

    I'm not super particular with the exact naming here and would be happy to move to something like RateLimitExceeded if others think this is better, but on initial glance exactly matching the corresponding code from the HTTP spec seemed valuable.

    Why not use the existing ResourceExhausted error code to indicate the client should slow down

    Technically, exceeding a rate limit could be considered "exhausting a per-user quota" and be represented by the existing ResourceExhausted error. However, on first glance, my interpretation of receiving a ResourceExhausted error code as a client caller is that something is problematic or damaged on the server, not that my request pattern as a client is faulty. In fact, the Twirp service may be completely healthy, but choose to reject a client's traffic because it breaks some negotiated rate limit, even if it could handle the traffic just fine without exhausting its resources. In addition, there are many potential situations where there are no user-level limits and yet rate limiting is still expected. For example, a Twirp service may place global rate limit across all callers on a very expensive API operation to ensure a downstream remains healthy.

    Secondly, breaking this out into its own error code allows the very simple creation of rate-limiting Twirp middleware via ServerHooks. If we chose to reuse the existing ResourceExhausted error code, any middleware would have to inspect both the error code as well as actual error message to ensure that the ResourceExhausted error received was due to rate limiting instead of some other generic resource exhaustion. Checking the error message directly is more brittle to changes.

    In my mind, having a error code that either strictly or loosely correlates with the 429 TooManyRequests error code from the HTTP spec is valuable for both Twirp clients, service developers and the Twirp ecosystem as a whole.

    By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

  • Allow generation of Twirp in a different Golang Package

    Allow generation of Twirp in a different Golang Package

    I'll keep this pretty short for now (I also know we discussed this very briefly @spenczar) but just to get the conversation going since this is on my near-term radar:

    • It would be nice to be able to have twitchtv/twirp generated code in a different package than the golang/protobuf generated code. This in theory would allow you to have separation of your Protobuf definitions and the specific RPC protocol you use. For example, I'd love to have:

    • foo/barpb - Protobuf messages for package foo.bar

    • foo/twitchbarpb - Twirp client/servers for package foo.bar

    • foo/grpcbarpb - gRPC client/servers for package foo.bar - I'm not sure if this is will be allowed with the new protoc-gen-go-grpc via https://github.com/protocolbuffers/protobuf-go/blob/master/compiler/protogen/protogen.go but we can leave this out of it

    • foo/magicbarpb - My custom magical RPC implementation (not in reality but as an example)

    What this would require is protoc-gen-twirp recognizing when it was generating code in a different package than the package of the golang/protobuf generated code, and then generating imports, ie:

    // all shorthand, not even importing context
    import barpb "github.com/alice/bob/foo/barpb"
    
    type EchoService interface {
      Echo(context.Context, *barpb.EchoRequest) (*barpb.EchoResponse, error)
    }
    

    This might be able to be implemented with some combination of the Mkey=value (which would be annoying), import_path, and import_prefix options, but honestly it would be so much easier if there was just a definition_path=github.com/alice/bob/foo/barpb option or something similar to just denote this easily. There are Golang Protobuf plugin libraries that handle this kind of behavior, so there's a lot of work to pattern off of.

    Thoughts?

  • Add support for custom route prefixes

    Add support for custom route prefixes

    Hello,

    I was really excited to read about twirp and want to undertake a project with it. Unfortunately, twirp seems to make some pretty opinionated decisions about my API's pathing. I've noticed that the generator prepends the literal "twirp" to the url, and seems to require the services internal name be exposed. I'm not familiar with writing proto generators but I assume it is possible to provide some sort of generator option to disable or customize this functionality.

    For the hard coded /twirp, I'm wondering if this is a twitch specific thing or if you're open to removing it. Considering I can use my own mux, I'm capable of prepending paths already.

    For the service name, it seems a bit less straight forward. It is possible to expose the handlers so they can be plugged directly into the mux. I guess the apprehension is keeping twirp from becoming a complex mux in and of itself, but I think it can be made possible without convoluting the code base.

  • Handle the standard M= and import_prefix= golang plugin flags

    Handle the standard M= and import_prefix= golang plugin flags

    Example: https://github.com/yarpc/yarpc-go/blob/dev/internal/protoplugin/runner.go#L50

    Will be needed when request/response types are outside of the package of the service, or if generating the Twirp handlers to a different golang package.

    Nice work by the way!

  • Making logging to stdout optional

    Making logging to stdout optional

    The generated twirp servers include import log "log"

    They're used in error cases like this:

    	if _, err = resp.Write(buf.Bytes()); err != nil {
    		log.Printf("errored while writing response to client, but already sent response status code to 200: %s", err)
    	}
    

    It would be great if I could provide my own logger of some kind.

    One proposed API would be to expose an optional function I could type assert for.

    func (s *myServer) SetLogger(logger *log.Logger) {
      s.logger = logger
    }
    

    The client code could then call

    x := NewMyServer(...)
    x.(twirp.Logthingie).SetLogger(myOwnLogger)
    

    If you're ambitious, you could have a specific twirp type logger for more strongly typed information

    type TwirpLogger interface {
      ErrorWritingReponse(ctx context.Context, writeErr err)
    }
    

    My implementation could then extract the method name from the ctx.

  • Support an optional ErrorCoder interface for Go servers

    Support an optional ErrorCoder interface for Go servers

    This is a proposal for an improvement to how Twirp handlers return errors. I originally brought this up a couple of years ago on the Twirp Slack in a discussion with @spenczar and @marwan-at-work.

    To summarize, I propose that we add the following interface to the twirp package. A detailed proposal with background information follows.

    // ErrorCoder may be implemented by third-party error types returned by
    // Twirp handler functions to indicate a Twirp error code to report.
    //
    // If a non-nil error e returned by a handler is not an Error but is an
    // ErrorCoder (or wraps one as indicated by errors.As), the server responds
    // with an error using the code given by e.TwirpErrorCode and a message
    // given by e.Error.
    type ErrorCoder interface {
    	TwirpErrorCode() ErrorCode
    }
    

    If this proposal is acceptable, I'm happy to send a PR.


    Background

    At my company we use Twirp extensively for making RPCs across systems. We sometimes need to convey particular error conditions (entity not found, say) and handle them differently on the client side. We can do this by sending a particular Twirp error code as the response.

    The way this works today is that if a handler returns an error that implements twirp.Error, that Twirp error is used for the response. If the handler returns a non-nil error that does not implement twirp.Error, then it is considered a generic internal error and wrapped using twirp.InternalErrorWith.

    This works well enough if the handler makes decisions about different error conditions directly. However, if the error is created a few functions down the call chain, it works less well:

    • The function that generates the error might not be Twirp-specific, so it's not appropriate to return a twirp.Error, which is very much Twirp-specific. For instance, we have some servers that have shared internal logic which is used for generating web pages as well as Twirp responses and we don't want to generate Twirp errors in non-Twirp routes.
    • The error generated down the call stack might be wrapped with other errors before the handler route gets it.

    To work around this issue, a common pattern is for our servers to use a function to match errors to various internal error variables/types and return the appropriate Twirp error:

    func toTwirpError(err error) error {
    	switch {
    	case errors.Is(err, errJobFinished):
    		return twirp.NewError(twirp.FailedPrecondition, err.Error())
    	case errors.Is(err, errNoLogDataAfterWait):
    		return twirp.NewError(twirp.DeadlineExceeded, err.Error())
    	case errors.As(err, new(jobNotFoundError)):
    		return twirp.NotFoundError(err.Error())
    	// ... several more cases ...
    	default:
    		return err
    	}
    }
    

    All handlers have to remember to call toTwirpError any time they are returning the results of some function call that might return one of these internal errors. This is tedious and easy to mess up. It also happens to be fairly inefficient.

    Proposal

    We propose to add the ErrorCoder interface described above.

    The idea is that the generated handler code will look something like this:

    func writeError(ctx context.Context, resp http.ResponseWriter, err error, hooks *twirp.ServerHooks) {
    	// If we already have a twirp.Error, use it.
    	twerr, ok := err.(twirp.Error)
    	if !ok {
    		var ec twirp.ErrorCoder
    		if errors.As(err, &ec) {
    			// If we have a twirp.ErrorCoder, use the error code it
    			// provides.
    			twerr = twirp.NewError(ec.TwirpErrorCode(), err.Error())
    		} else {
    			// Otherwise, non-twirp errors are wrapped as Internal by default.
    			twerr = twirp.InternalErrorWith(err)
    		}
    	}
    	// ...
    }
    

    This allows us to create internal error types for each project which which are not Twirp-specific but can be turned into Twirp errors because they correspond to a Twirp error code. We can freely return those from any function whether or not it's being called as part of a Twirp route and even wrap them as they go up the call stack.

    Backward compatibility

    This is fully backward compatible and doesn't change the behavior of any existing code.

    (Technically speaking, it could change the behavior of code which uses an error type which has a method TwirpErrorCode() twirp.ErrorCode, but that seems very unlikely.)

    Alternatives

    One slight variant on this interface which would be slightly more flexible but require a little more boilerplate to implement would be to have the optional method return a Twirp Error rather than just the ErrorCode:

    type Errorer interface {
    	TwirpError() Error
    }
    

    Naming

    I think it's important that the method is called TwirpErrorCode, not ErrorCode, because the purpose of the interface is to be implemented by types outside of a Twirp context and so it's good for the method to make it clear that it is a Twirp-related adapter.

    If the method is TwirpErrorCode, you could then argue that the interface should be TwirpErrorCoder, though it's a little redundant with the package name: twirp.TwirpErrorCoder. I don't have a strong feeling about this, though. (The interface itself should rarely be named in any code.)

  • Allow JSON lowerCamelCase names

    Allow JSON lowerCamelCase names

    Relates to #84. My organization has some tooling that expects lowerCamelCase fields and Twirp currently does not allow you configure this behavior. Mirrors implementation of similar option added in https://github.com/twitchtv/twirp/pull/271.

  • TwirpServer Constructor not capturing ServerOptions in v8.1.2

    TwirpServer Constructor not capturing ServerOptions in v8.1.2

    Hello, I am fairly new to Twirp so this may be something I am doing wrong. We recently upgraded from github.com/twitchtv/twirp/[email protected] to github.com/twitchtv/twirp/[email protected].

    We have a service called Builder which we are instantiating in the router.go of our application using:

    builderHandler := rpc.NewBuilderServer(d.handlers.builder, tw.DefaultOptions(), twirp.WithServerPathPrefix(pathPrefix))
    

    Here is the definition of tw.DefaultOptions():

    func DefaultOptions() twirp.ServerOption {
    	options := func(o *twirp.ServerOptions) {
    		o.JSONSkipDefaults = true
    		o.Hooks = defaultHooks()
    	}
    	return options
    }
    

    The NewBuilderServer Twirp function gets defined as follows in v8.1.2:

    func NewBuilderServer(svc Builder, opts ...interface{}) TwirpServer {
    	serverOpts := newServerOpts(opts)
    
    	// Using ReadOpt allows backwards and forwads compatibility with new options in the future
    	jsonSkipDefaults := false
    	_ = serverOpts.ReadOpt("jsonSkipDefaults", &jsonSkipDefaults)
    	jsonCamelCase := false
    	_ = serverOpts.ReadOpt("jsonCamelCase", &jsonCamelCase)
    	var pathPrefix string
    	if ok := serverOpts.ReadOpt("pathPrefix", &pathPrefix); !ok {
    		pathPrefix = "/twirp" // default prefix
    	}
    
    	return &builderServer{
    		Builder:          svc,
    		hooks:            serverOpts.Hooks,
    		interceptor:      twirp.ChainInterceptors(serverOpts.Interceptors...),
    		pathPrefix:       pathPrefix,
    		jsonSkipDefaults: jsonSkipDefaults,
    		jsonCamelCase:    jsonCamelCase,
    	}
    }
    

    The issue here is that, as we can see in the definition of tw.DefaultOptions(), jsonSkipDefaults should be set to true. However, _ = serverOpts.ReadOpt("jsonSkipDefaults", &jsonSkipDefaults) does not change the value of jsonSkipDefaults and leaves it as false.

    For context here is how the NewBuilderServer Twirp function gets defined in v8.0.0:

    func NewBuilderServer(svc Builder, opts ...interface{}) TwirpServer {
    	serverOpts := twirp.ServerOptions{}
    	for _, opt := range opts {
    		switch o := opt.(type) {
    		case twirp.ServerOption:
    			o(&serverOpts)
    		case *twirp.ServerHooks: // backwards compatibility, allow to specify hooks as an argument
    			twirp.WithServerHooks(o)(&serverOpts)
    		case nil: // backwards compatibility, allow nil value for the argument
    			continue
    		default:
    			panic(fmt.Sprintf("Invalid option type %T on NewBuilderServer", o))
    		}
    	}
    
    	return &builderServer{
    		Builder:          svc,
    		pathPrefix:       serverOpts.PathPrefix(),
    		interceptor:      twirp.ChainInterceptors(serverOpts.Interceptors...),
    		hooks:            serverOpts.Hooks,
    		jsonSkipDefaults: serverOpts.JSONSkipDefaults,
    	}
    }
    

    This works as expected. These two pieces of code are semantically identical for our purposes. I was wondering if I could get some help in determining what could be causing an issue like this to occur. Any guidance will be greatly appreciated!

  • Go package imported twice if proto package split into multiple files

    Go package imported twice if proto package split into multiple files

    If this is intended behavior, my bad. I tried searching through issues and I couldn't find much.

    I have the following proto file (where I have just services defined):

    // file services.proto
    syntax = "proto3";
    
    package rpc;
    option go_package = "github.com/lrstanley/spectrograph/internal/rpc";
    
    import "google/protobuf/empty.proto";
    import "internal/models/protos/servers.proto";
    import "internal/models/protos/worker.proto";
    
    service Worker {
        rpc Health(google.protobuf.Empty) returns (models.WorkerHealth); // models.WorkerHealth being from worker.proto
        rpc UpdateServer(models.ServerDiscordData) returns (google.protobuf.Empty); // models.ServerDiscordData being from servers.proto
        rpc UpdateServerStatus(models.ServerStatus) returns (google.protobuf.Empty); // models.ServerStatus being from servers.proto
    }
    

    It has two imports:

    import "internal/models/protos/servers.proto";
    import "internal/models/protos/worker.proto";
    

    Both of these imports are within the same directory of eachother, but not in the directory of the services/twirp files, and both actually specify the same go_package and package line, as they're only split into multiple files given the size and specific-scope of the messages:

    // file: servers.proto
    syntax = "proto3";
    
    package models;
    option go_package = "github.com/lrstanley/spectrograph/internal/models";
    
    [... server-specific messages defined below...]
    
    // file: worker.proto
    syntax = "proto3";
    
    package models;
    option go_package = "github.com/lrstanley/spectrograph/internal/models";
    
    [... worker-specific messages defined below...]
    

    I am able to import both and use them successfully. However, I noticed the generated *.twirp.go files have:

    import models "github.com/lrstanley/spectrograph/internal/models"
    import models1 "github.com/lrstanley/spectrograph/internal/models"
    

    And reference the same go_package as multiple imports throughout the file, which can be rather confusing.

    This works successfully (it's supported behavior by protobuf, and from my understanding, not discouraged), however I'm wondering if we can add some logic that ensures if there are multiple imports with the same exact go package name and path, that only one line is imported?

    The more serious issue I suspect is: if the current behavior could cause issues for those that use init() functions in their Go packages, where the *.pb.go files are generated, as I suspect these would get executed twice. I.e. if variables or similar are initialized, this could cause weird state issues for users, where two sets of initialized state are used.

  • Support Go Modules

    Support Go Modules

    Twirp should be able to support Go Modules for a few reasons:

    1. Pinning dependencies correctly when GO111MODULE will be set to on by default in the next release of Go 1.13

    2. It will make the onboarding experience to twirp a little bit easier because you'll be able to get binaries such as protoc-gen-twirp at an exact version without having to use retool. For example: go get github.com/twitchtv/twirp/[email protected]

    3. There will be no need to vendor dependencies on both the twirp side as well as the user's side.

    I noticed that there was already an issue about adding go.mod/go.sum and the reason for closing it was this comment: https://github.com/twitchtv/twirp/issues/140#issuecomment-452401108

    In particular:

    the transition will involve quite a bit more than just adding go.mod and go.sum files as import paths will need to change

    For that reason, I created a tool to automatically upgrade import paths.

    I have a draft PR to demonstrate that all import paths are upgraded and that the tests past (at least locally for me).

    The PR is in draft because A. I'm not familiar with Twirp's roadmap and B. I imagine a lot of documentation needs to be updated to show the new flow of getting started.

    Please feel free to keep this open until Twirp officially supports module, and also feel free to add all the TODOs that need to be accomplished before rendering this issue resolved.

  • Proposal: Support streaming in the Twirp spec

    Proposal: Support streaming in the Twirp spec

    I think this is a great addition for RPC for Go (as well as other languages!). The main thing that I expect will limit adoption is the lack of streaming support. There are mechanisms to do streaming on http/1.x (a great example is the grpc-gateway stuff) where they effectively just use chunked encoding with blobs to do the streaming.

JSON-annotated protobuf definitions for NVD feeds

PROTONVD: Protobuf definitions for NVD Features: Encapsulates all fields in the NIST NVD Vulnerability JSON feeds. JSON annotations in proto definitio

Feb 17, 2022
protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text formats

protoCURL protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text forma

Aug 26, 2022
Control your Flipper Zero over Protobuf RPC protocol.

go-flipper Control your Flipper Zero over Protobuf RPC protocol. This library is designed to be transport agnostic, though I've tested it with RPC ove

Aug 25, 2022
Antenna RPC is an RPC protocol for distributed computing, it's based on QUIC and Colfer. its currently an WIP.

aRPC - Antenna Remote Procedure Call Antenna remote procedure call (aRPC) is an RPC protocol focused on distributed processing and HPC. aRPC is implem

Jun 16, 2021
rpc/v2 support for JSON-RPC 2.0 Specification.

rpc rpc/v2 support for JSON-RPC 2.0 Specification. gorilla/rpc is a foundation for RPC over HTTP services, providing access to the exported methods of

Jul 4, 2021
Go Substrate RPC Client (GSRPC)Go Substrate RPC Client (GSRPC)

Go Substrate RPC Client (GSRPC) Substrate RPC client in Go. It provides APIs and types around Polkadot and any Substrate-based chain RPC calls. This c

Nov 11, 2021
GSRPC compatible type definitions of events from the ChainBridge substrate pallet

chainbridge-substrate-events GSRPC compatible type definitions of events from the ChainBridge substrate pallet. ChainSafe Security Policy Reporting a

Nov 13, 2021
Gotypegraph - Generate definitions and references graph

gotypegraph Generate definitions and references graph. Usage ❯ gotypegraph -h Us

Feb 15, 2022
Orion - a small lightweight framework written around grpc/protobuf with the aim to shorten time to build microservices at Carousell.

Orion Orion is a small lightweight framework written around grpc/protobuf with the aim to shorten time to build microservices at Carousell. It is deri

Sep 7, 2022
Service that calls uzma24/project1 service, takes input from .txt file and prints JSON output returned from the service.

Service that calls uzma24/project1 service, takes input from .txt file and prints JSON output returned from the service. Program can take large input files.

Feb 6, 2022
A Light Golang RPC Framework

Glory Glory框架为一款Go语言的轻量级RPC框架,您可以使用它快速开发你的服务实例。如果您希望在微服务场景下使用gRPC进行网络通信,那么Glory会使您的开发、运维工作量减轻不少。 欢迎访问Glory主页: glory-go.github.io 示例仓库:github.com/glory

Aug 4, 2022
Netpoll is a high-performance non-blocking I/O networking framework, which focused on RPC scenarios, developed by ByteDance.
Netpoll is a high-performance non-blocking I/O networking framework, which focused on RPC scenarios, developed by ByteDance.

Netpoll is a high-performance non-blocking I/O networking framework, which focused on RPC scenarios, developed by ByteDance. RPC is usually heavy on processing logic and therefore cannot handle I/O serially. But Go's standard library net designed blocking I/O API, so that the RPC framework can only follow the One Conn One Goroutine design.

Sep 16, 2022
Fast and Scalable RPC Framework

Rony (Fast and Scalable RPC Framework) About Rony lets you create a clustered aware service easily. Checkout Wiki Performance Rony is very fast and wi

Jun 13, 2022
A local meetup to show some of the features of the Twirp RPC framework

twirpdemo This repo was created for a local meetup to show some of the features of the Twirp RPC framework. Usage Generate proto code: protoc --twirp

Sep 6, 2022
Gbio - Extremely minimalist RPC framework - Go but interface only

gbio !!! ?? WIP ?? !!! Go but interface only. gbio is a(n): Extremely minimalist

Jan 3, 2022
Protobuf files manager

Prot - protobuf files manager. It application can help your manage protobuf files and generate code based on him. !!! Before use Prot you must install

Jun 22, 2022
A Protocol Buffers compiler that generates optimized marshaling & unmarshaling Go code for ProtoBuf APIv2

vtprotobuf, the Vitess Protocol Buffers compiler This repository provides the protoc-gen-go-vtproto plug-in for protoc, which is used by Vitess to gen

Sep 25, 2022
protobuf ではなく JSON でやり取りするファイルを出力する protoc プラグイン

protoc-gen-jsonif proto ファイルから、JSON フォーマットでやりとりする型定義ファイルを出力する protoc プラグインです。 proto ファイルで言語を越えて型定義が出来るのはとても良い しかし protobuf ライブラリを入れるのが面倒 今のプロジェクトには既に

Feb 28, 2022
WIP protobuf support for Gleam ✨

gleam_pb WIP protobuf support for Gleam ✨ Progress Gleam Type generation custom functions that better handle default values stop including unnecessary

Feb 26, 2022