TwirpScript
A protobuf RPC framework for JavaScript and TypeScript
Install / Use
/learn @tatethurston/TwirpScriptREADME
TwirpScript
<blockquote> A protobuf RPC framework for JavaScript and TypeScript</blockquote> <br /> <a href="https://www.npmjs.com/package/twirpscript"> <img src="https://img.shields.io/npm/v/twirpscript.svg"> </a> <a href="https://github.com/tatethurston/twirpscript/blob/master/LICENSE"> <img src="https://img.shields.io/npm/l/twirpscript.svg"> </a> <a href="https://www.npmjs.com/package/twirpscript"> <img src="https://img.shields.io/npm/dy/twirpscript.svg"> </a> <a href="https://github.com/tatethurston/twirpscript/actions/workflows/ci.yml"> <img src="https://github.com/tatethurston/twirpscript/actions/workflows/ci.yml/badge.svg"> </a> <a href="https://codecov.io/gh/tatethurston/twirpscript"> <img src="https://img.shields.io/codecov/c/github/tatethurston/twirpscript/main.svg?style=flat-square"> </a>What is this? 🧐
TwirpScript is an implementation of Twirp. TwirpScript autogenerates Javascript or TypeScript clients and servers from protocol buffers. The generated clients can be used in browser or Node.js runtimes, enabling type safe communication between web applications and a server or server-to-server. TwirpScript implements the latest Twirp Wire Protocol (v7).
| Language | Clients | Servers | | -------------- | ------- | ------- | | JavaScript | ✅ | ✅ | | Typescript | ✅ | ✅ |
Table of Contents
- Overview
- Highlights 🛠
- Installation 📦
- Getting Started
- Requirements ⚠️
- Configuration 🛠
- JSON
- Examples 🚀
- Working with other tools
- Caveats, Warnings and Issues ⚠️
- FAQ
- Contributing 👫
- Licensing 📃
Overview
Twirp is a simple RPC framework built on protocol buffers. TwirpScript generates JavaScript or TypeScript clients and servers from .proto service specifications. The generated clients can be used in the browser or in Node.js runtimes. This enables type safe communication between the client and server, as well as reduced payload sizes when using protobuf as the serialization format.
You define your service in a .proto specification file, and TwirpScript will generate client and service handlers for that service. You fill in the business logic that powers the server, and TwirpScript handles the boilerplate.
To learn more about the motivation behind Twirp (and a comparison to REST APIs and gRPC), check out the announcement blog.
Highlights 🛠
-
Isomorphic. TwirpScript's generated serializers/deserializers can be consumed in the browser or Node.js runtimes.
-
Small. TwirpScript's runtime and generated code are built with tree shaking to minimize bundle sizes. This results in a significantly smaller bundle size than google-protobuf. TwirpScript's runtime is 2KB (1.2 gzipped). The serialization runtime, ProtoScript, is 37KB (7.2 gzipped). ProtoScript will be eliminated from bundles when only using the generated JSON clients.
-
In-editor API documentation. Comments in your
.protofiles become TSDoc comments in the generated code and will show inline documentation in supported editors. -
Idiomatic JavaScript / TypeScript code. None of the Java idioms that
protoc --js_outgenerates such as theListsuffix naming for repeated fields,Mapsuffix for maps, or the various getter and setter methods. TwirpScript generates and consumes plain JavaScript objects over classes.
Installation 📦
-
Install the protocol buffers compiler:
MacOS:
brew install protobufLinux:
apt install -y protobuf-compilerWindows:
choco install protocOr install from a precompiled binary.
-
Add this package to your project:
npm install twirpscriptoryarn add twirpscript
Requirements ⚠️
- Node.js v16 or greater
- TypeScript v4.7 or greater when using TypeScript
Getting Started
Overview 📖
- Define your service in a
.protofile. - Run
npx twirpscriptto generate JavaScript or TypeScript code from your.protofile. This will generate JSON and Protobuf clients, a service interface, and service utilities. - If you only need a client, you're done! Use the generated client to make requests to your server.
- Implement the generated service interface.
- Add your implemented service to your application server's routes.
1. Define your service
Create a proto specification file:
src/protos/haberdasher.proto
syntax = "proto3";
// Haberdasher service makes hats for clients.
service Haberdasher {
// MakeHat produces a hat of mysterious, randomly-selected color!
rpc MakeHat(Size) returns (Hat);
}
// Size of a Hat, in inches.
message Size {
int32 inches = 1; // must be > 0
}
// A Hat is a piece of headwear made by a Haberdasher.
message Hat {
int32 inches = 1;
string color = 2; // anything but "invisible"
string name = 3; // i.e. "bowler"
}
2. Run npx twirpscript
This will generate haberdasher.pb.ts (or haberdasher.pb.js for JavaScript users) in the same directory as as haberdasher.proto. Any comments will become TSDoc comments and will show inline in supported editors.
npx twirpscript will compile all.proto files in your project.
3. Use the client
Use the generated clients to make json or protobuf requests to your server:
src/client.ts
import { client } from "twirpscript";
import { MakeHat } from "../protos/haberdasher.pb";
client.baseURL = "http://localhost:8080";
const hat = await MakeHat({ inches: 12 });
console.log(hat);
The above client code may be used in browser or node.js runtimes. See a Node.js client example.
If you have an existing Twirp server you're connecting to and only need a client, that's it! You're done. If you're implementing a service as well, keep reading.
4. Implement the generated service interface
src/server/haberdasher/index.ts
import { Haberdasher, createHaberdasher } from "../../protos/haberdasher.pb";
const haberdasher: Haberdasher = {
MakeHat: (size) => {
return {
inches: size.inches,
color: "red",
name: "fedora",
};
},
};
export const haberdasherHandler = createHaberdasher(haberdasher);
5. Connect your service to your application server
src/server/index.ts
import { createServer } from "http";
import { createTwirpServer } from "twirpscript";
import { haberdasherHandler } from "./haberdasher";
const PORT = 8080;
const app = createTwirpServer([haberdasherHandler]);
createServer(app).listen(PORT, () =>
console.log(`Server listening on port ${PORT}`),
);
If you're deploying to a serverless environment such as AWS Lambda, replace createTwirpServer above with createTwirpServerless. See the aws lambda example for a full project!
Configuring your Twirp Runtime
Client
Clients can be configured globally, at the RPC callsite, or with middleware. The order of precedence is middleware > call site configuration > global configuration. Middleware overrides call site configuration, and call site configuration overrides global configuration.
Configuration Options
| Name | Description | Type | Example | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ---------------------------- | | baseURL | The base URL for the RPC. The service path will be appended to this string. | string | "https://my.server.com/" | | headers | HTTP headers to include in the RPC. | Record<string, string> | { "idempotency-key": "foo" } | | prefix | A path prefix such as "/my/custom/prefix". Defaults to "/twirp", but can be set to "". | string
Related Skills
node-connect
346.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
107.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
346.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
346.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
