Library / SDK
webrpc/webrpc avatar
webrpc/webrpc

webrpc turns one schema file into a server and a typed client

webrpc is a schema-driven approach to writing apis with code generation of full client libraries in many languages

828 stars56 forksGoMIT

At a glance

What is it?
webrpc is a Go meta-protocol with a code generator that reads a RIDL schema and emits server interfaces, JSON encoders and complete client libraries for seven languages, and it trades gRPC's binary transport for JSON over HTTP so ordinary browsers and curl work unchanged.
Who is it for?
webrpc suits a team writing a web backend with several client applications, especially one where a Go server and a TypeScript front end have to agree on request and response shapes, and it suits anyone who wants a typed client without adopting a binary transport that browsers cannot call.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One schema, then a generator writes both ends

webrpc is described as a schema-driven approach to writing backend servers for the web, and the workflow is four steps. You install the webrpc-gen binary, you write the interface of your service in a schema file in RIDL or JSON format, you run the generator, and you implement the handlers, because as the README puts it, the generator cannot guess your server logic. What comes out is more than types. From the schema it generates application base class types and interfaces, JSON encoders, and networking code, and in doing so it produces fully functioning typed client libraries. The pitch in the README is that you get strongly typed web services and never have to write an API client library again. The audience is a team that has a server and more than one client language, and the alternative to adopting it is a set of hand written clients that drift out of sync with the server.

The RIDL schema is the contract, errors included

The example schema in the README shows what a service definition looks like, and the format is close to a documentation language.

text
webrpc = v1

name = your-app
version = v1.0.0
basepath = /v1

service ExampleService
  - Ping()
  - Status() => (status: bool)
  - GetUserByID(userID: uint64) => (user: User)
  - IsOnline(user: User) => (online: bool)
  - ListUsers(q?: UsersQueryFilter) => (page: uint32, users: []User)

struct User
  - id: uint64
  - username: string
  - createdAt?: timestamp

A method is a name with optional parameters and a return signature, structs are named field lists, and the optional marker on a field or a parameter is part of the type, so a client knows whether a value may be absent. Errors are declared in the same file with a code, a name, a message and an HTTP status, which is what makes the generated client able to distinguish a rate limit from a service outage without string matching. The README notes that basepath defaults to /rpc/ when services are defined and that version will also be required when services are defined, both of which will become mandatory in a future release, so a schema written today should set them explicitly.

Seven generators, and only three of them make a server

The generator table is the practical shape of the project. The targets are Go for Go 1.24 and newer, TypeScript for ES2022 and newer, JavaScript for ES6, Kotlin with coroutines and kotlinx.serialization, Dart for 3.1 and newer, Swift for 5.9 and newer, and OpenAPI 3.0.0. All seven work with the v1 schema. Client generation is marked as available for every one of them. Server generation is available for Go, TypeScript, JavaScript and OpenAPI, and the table shows blank server cells for Kotlin, Dart and Swift, so those four are client-only targets. The OpenAPI row carries footnotes linking to swagger-codegen, which points to the generator being used for that target. The README also says the generators are just Go templates, in the same family as Hugo templates or Helm charts, and invites contributions, which means a new language target is a template file rather than a new project.

The generator call is one long command line

The getting started section shows the two typical invocations, one producing a Go server and client and one producing a TypeScript client.

bash
webrpc-gen -schema=example.ridl -target=golang -pkg=main -server -client -out=./example.gen.go
bash
webrpc-gen -schema=example.ridl -target=typescript -client -out=./web/client.ts

The flags are the schema path, the target, the package name for Go, the server and client switches and the output file. There is no separate step for types or encoders, because the same command emits them alongside the client. The README also points at the example apps as a shortcut, listing hello-webrpc for a Go server with a JavaScript web app, hello-webrpc-ts for the TypeScript variant, golang-basics for a Go server with a Go client, golang-nodejs for a Go server with a Node.js client, and node-ts for a Node.js server with a TypeScript client. That last pair is the one that shows the scheme is not tied to a Go server, even though the tool itself is written in Go.

The transport choice is the whole argument against gRPC

The Why section of the README puts it as a short version: it is much simpler and faster to write and consume a webrpc service than traditional approaches like a REST API or a gRPC service. The concrete claim behind that is compatibility with the web. A webrpc server is just an HTTP or HTTPS server that speaks JSON, so existing browsers, HTTP clients, load balancers, proxies, caches and tools work out of the box, and curl just works, where the README draws the contrast with gRPC. The problem the project describes is the cost of the full cycle for a REST service: designing the routes, agreeing on conventions with the team, defining the request and response payloads, writing the server logic, wiring the methods to the handlers, and then writing a client library in whichever language the consumer uses. webrpc automates the parts of that list which are mechanical, and the type-safety question across the wire is answered by generating both ends from the same file. The cost of the choice is that everything is JSON, so a gRPC service with a binary payload and a streaming call has no direct equivalent here.

Building it is a Go build and a stamped version string

The project itself is a Go module, github.com/webrpc/webrpc, requiring Go 1.25.11 and stating that it supports the two most recent major versions of Go. The Makefile stamps the version into the binaries with the same ldflags pattern for webrpc-gen and webrpc-test, and the version falls back to a development string in a checkout with no git tags, which the comment explains is for fork pull request checkouts in CI.

bash
build:
	go build -ldflags="-s -w -X github.com/webrpc/webrpc.VERSION=$(VERSION)" -o ./bin/webrpc-gen ./cmd/webrpc-gen

The generate target is the interesting one for a contributor. It runs go generate over the whole tree, then loops over every directory in _examples and regenerates each one, then regenerates the interop-web test, and finally rewrites the version string out of the generated files to avoid git conflicts. That last step is a small thing that says a lot: the generated output is committed, so the build has to be reproducible without the version stamp leaking into the diff. The Dockerfile does the same thing in two stages, building the generator from a golang alpine image with the version passed as a build argument and copying the binary into an alpine runner that has only ca-certificates installed.

Where a JSON RPC schema is the wrong tool

Three limits are visible in the README and the generator table. The first is that the generated client is only useful to consumers who use it, so a public API with third party clients still needs conventional documentation and a hand written or OpenAPI description, and the OpenAPI target exists precisely because other ecosystems need that. The second is the breadth of the language support versus its depth: seven targets is a lot, but the server side exists for only three, and a team that needs a Kotlin or Swift service has to build it by hand and hand maintain the schema contract that the Go generator would otherwise enforce. The third is the transport, and it is not a small one. A schema-driven RPC layer over JSON is a good fit for request and response services, and a poor fit for anything with streaming, for long lived connections, or for a service whose payload is large enough that JSON encoding shows up in a profile. The README positions webrpc as a web service meta-protocol rather than a gRPC replacement, and that positioning is the honest reading.

Editorial conclusion

webrpc suits a team writing a web backend with several client applications, especially one where a Go server and a TypeScript front end have to agree on request and response shapes, and it suits anyone who wants a typed client without adopting a binary transport that browsers cannot call. It is the wrong choice for a public API consumed by third parties who will not use your generated client, and it is the wrong choice if you need streaming or the tooling ecosystem that surrounds gRPC and OpenAPI. Before adopting it, look at the seven generator targets and confirm the language pair you need is among them, note that only three of the seven generate a server, and read the basepath and version rules, because the README says both will become required in a future release. The last push was on 2026-10-19 and the current release is v0.48.0 from the same day.

Frequently asked questions

What is webrpc and how does the code generation work?

webrpc is a schema-driven approach to writing backend servers. You write the service interface in a RIDL or JSON schema file and run webrpc-gen, which generates the application base class types and interfaces, JSON encoders, networking code and complete typed client libraries for the target language.

Which languages does webrpc generate code for?

Seven targets are listed: Go, TypeScript, JavaScript, Kotlin, Dart, Swift and OpenAPI 3.0.0. Client generation is available for all of them, while server generation is only marked for Go, TypeScript, JavaScript and OpenAPI. The generators are Go templates, and the README invites contributions for more.

How do I run the webrpc code generator?

Install the webrpc-gen release, then run it with a schema, a target and the switches for the output you want, for example webrpc-gen -schema=example.ridl -target=golang -pkg=main -server -client -out=./example.gen.go for a Go server and client.

How does a webrpc server differ from a gRPC service?

A webrpc server is an HTTP or HTTPS server that speaks JSON, so browsers, HTTP clients, load balancers, proxies, caches and tools such as curl work with it out of the box, which the README contrasts with gRPC. The trade-off is that everything is JSON, so there is no equivalent of a binary payload or a streaming call.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. webrpc/webrpc on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/webrpc-webrpc.svg)](https://hysenlabs.com/projects/webrpc-webrpc)

Was this useful?