SkillAgentSearch skills...

TwirpScript

A protobuf RPC framework for JavaScript and TypeScript

Install / Use

/learn @tatethurston/TwirpScript
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

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

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 🛠

  1. Isomorphic. TwirpScript's generated serializers/deserializers can be consumed in the browser or Node.js runtimes.

  2. 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.

  3. In-editor API documentation. Comments in your .proto files become TSDoc comments in the generated code and will show inline documentation in supported editors.

  4. Idiomatic JavaScript / TypeScript code. None of the Java idioms that protoc --js_out generates such as the List suffix naming for repeated fields, Map suffix for maps, or the various getter and setter methods. TwirpScript generates and consumes plain JavaScript objects over classes.

Installation 📦

  1. Install the protocol buffers compiler:

    MacOS: brew install protobuf

    Linux: apt install -y protobuf-compiler

    Windows: choco install protoc

    Or install from a precompiled binary.

  2. Add this package to your project: npm install twirpscript or yarn add twirpscript

Requirements ⚠️

  • Node.js v16 or greater
  • TypeScript v4.7 or greater when using TypeScript

Getting Started

Overview 📖

  1. Define your service in a .proto file.
  2. Run npx twirpscript to generate JavaScript or TypeScript code from your .proto file. This will generate JSON and Protobuf clients, a service interface, and service utilities.
  3. If you only need a client, you're done! Use the generated client to make requests to your server.
  4. Implement the generated service interface.
  5. 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

View on GitHub
GitHub Stars154
CategoryDevelopment
Updated2mo ago
Forks14

Languages

TypeScript

Security Score

95/100

Audited on Feb 1, 2026

No findings