Warning: Buttery is still in alpha and is not (yet) suitable for production use. It CAN be used for side projects and game jams.
Buttery aims to be a minimalistic cross-platform language for defining type-safe RPCs and websockets. Buttery provides codegen and runtimes for browsers and node.js, with the intent of expanding to other platforms.
- Detailed language reference
node
target referencebrowser
target reference (incomplete)- Snailbook: an example nodejs app built on Buttery
Let's say we're building a basic chat app over websockets.
We define the interface in a .butt
(or alternatively .buttery
) file:
# chat.butt
service ChatService:
struct SendMessage:
timestamp: integer
content: string
struct NewMessageUpdate:
timestamp: integer
author: string
content: string
channel Chat:
incoming: SendMessage
outgoing: NewMessageUpdate
We generate a client and server via the cli:
$ buttery generate browser -f chat.butt
[ ... ]
$ buttery generate node -f chat.butt
[ ... ]
And consume the generated files in a sample client and server:
// client.ts on the frontend
import { ChatService } from "./buttery-genfiles/chat.browser";
const client = new ChatService("https://example.com");
const chatConnection = client.Chat();
chatConnection.listen((msg) => {
console.log(msg.content);
});
chatConnection.send({ timestamp: Date.now(), content: "Hello, world!" });
// server.ts on the backend
import {ButteryServer} from 'buttery-node';
import {ChatService} from './buttery-genfiles/chat.node'
const butteryServer = new ButteryServer();
butteryServer.implement(ChatService, "Chat", (connection) => {
connection.listen(msg => {
connection.send({
timetamp: Date.now(),
author: "Server"
content: 'Thanks for sending me a message!'
});
});
});
butteryServer.createServer().listen(8080);
Installation via npm, e.g. npm install -g buttery-cli
Buttery's CLI is very simple right now:
buttery generate <target environment> -f [files]
As an example call:
buttery generate browser -f ./path/to/file.butt
By default, this creates generated files in the buttery-genfiles
directory. This can be changed via the -o [path]
parameter. It's probably a good idea to gitignore that directory.
Buttery Clients
Target | Target Description | Support |
---|---|---|
browser | Generated Typescript for use in browsers | Full Support |
python-client | Generated code for Python Client | None |
Buttery Servers
Target | Target Description | Support |
---|---|---|
node | Generated Typescript for use in express backends | Full Support |
django | Generated code for use in Django backends | None |
Buttery aims to provide:
- A lightweight language for defining over-the-network APIs.
- First-class support for full duplex communication.
- Codegen for clients and servers in a variety of languages.
- Parsing and validation of requests and responses.
- (when applicable) Cross-language, cross network boundary type safety.
- Basic reliability abstractions, such as retries and message buffers for 2-way connections
Buttery does not aim to provide:
- Strong protections against version skew of specific definitions.
- Highly size-optimized over-the-wire encodings -- Buttery messages are valid JSON
- Support for non-evergreen browsers
- Backend to backend RPCs
- Frontend requests to backend services
- As a wrapper around websockets for server push
- Easy multiplexing of multiple services through a single host
Depending on your background, you might find one of these comparisons useful:
- A lightweight replacement for gRPC / protos, but over http(s) and websockets
- Twirp, but without all the baggage of protos, providing first-class support for browser -> backend comms, and bidi communication
- A lightweight replacement for swagger codegen, with bidi communication
- JSON-RPC-like specification, but paired with a small domain specific language for definitions and bidi communication