Introducing Spin
Matt Butcher
spin
Webassembly
wasm
wagi
We are pleased to announce our new WebAssembly framework, Spin. Spin is a foundational piece of the Fermyon Platform. It is also a great way to get started writing WebAssembly for the cloud.
What is a WebAssembly Framework?
We think of WebAssembly primarily as a compile target. Pick a language, write your code, and compile it to Wasm. But what kinds of code does one write in WebAssembly?
The original way to run a WebAssembly module was in the browser. For that reason, early WebAssembly effort was focused on optimizing performance-intensive code to be executed on a web page or client-side web app.
WebAssembly has now moved beyond the browser. Some platforms, like the Envoy proxy, allow you to write plugins in Wasm. Command line runtimes like Wasmtime and WAMR run Wasm binaries on the command line, allowing developers to write a single CLI application that can run on Windows, macOS, and Linux (regardless of the underlying architecture).
Here at Fermyon, we are most excited about the prospect of writing microservices and server-side web applications in WebAssembly. We gave a preview of this when we built Wagi. But with Spin, we’re taking things to a new level. Most specifically, Spin offers a framework for building apps.
What do we mean when we talk about a “framework”? A framework provides a set of features and conventions that assist a developer in reaching their desired goal faster and with less work. Ruby on Rails and Python Django are two good examples.
Spin is a framework for web apps, microservices, and other server-like applications. It provides the interfaces for writing WebAssembly modules that can do things like answer HTTP requests. One unique thing about Spin is that it is a multi-language framework. Rust and Go both have robust support in Spin, but you can also write Python, Ruby, AssemblyScript, Grain, C/C++, and other languages.
We are excited to already be using Spin in production. The Spin docs are (appropriately enough) running on Spin. That website is powered by the Bartholomew CMS system and is running on an HA Nomad cluster.
Spin is a foundational new technology that sets the pace for what we at Fermyon are building.
Spin is a Foundation
We have talked about the way we build applications in Spin. Part of the reason that Spin provides a framework is because by doing so, we can take advantage of some of the compelling features of WebAssembly. And in so doing, we can create serverless-style programs with many benefits.
Over the last few years, our discussions with developers have turned up some common themes:
- Ease of development is very important
- Function-as-a-Service systems like Lambda are nice to develop, but frustrating to operate
- Being locked into a proprietary platform is no fun
- Developers are not operators, and shouldn’t have to solve operations problems
As we built Spin, these ideas were foremost in our minds. We set out to build something that delivered on the promises of serverless, but had all the virtues of local development and modern frameworks. We’re building based on standards and open source tooling, and we’re working hard to please both developers and platform operators (including DevOps).
Beyond that, Spin has given us a chance to rethink microservices. When we built Wagi, our goal was to make something that worked with WebAssembly as it was in 2020. WebAssembly technology has gone through two highly productive years of development since then. Spin takes advantage of the new directions taken with WebAssembly, like components, WIT, and improvements to WASI (We’ll cover these things later in the post). Doing so has led us to build a framework that makes it easy for developers to achieve top-of-mind goals (like security) without having to spend countless cycles maintaining the low-level code.
Rather than explain further, let’s just look at an example. Here’s what a Spin “Hello World” looks like written in Rust:
#[http_component]
fn hello_world(_req: Request) -> Result<Response> {
Ok(Response::builder()
.status(200)
.body(Some("Hello, Fermyon!".into()))?)
}
Rust coder or not, most developers are familiar with the HTTP request/response model used here. Writing a Spin module is not much different in Go:
func main() {
spin.HandleRequest(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, Fermyon!")
})
}
Again, we just use the common request/response model that is idiomatic for Go.
Most important, though, is what we don’t have to do. There is no requirement that you create a web server to handle requests or start long-lived listeners or manage a pool for network connections. A Spin app can be as simple as a function. Of course, you can also add your preferred libraries to build out far more sophisticated apps… but at no time do you have to manage all of the low-level server duties like setting up SSL, handling interrupts, or wiring up sockets and ports. Such duties are delegated to Spin itself.
Following the model of stateless microservices, a Spin application can be bootstrapped, executed, and shut down again in milliseconds (or even nanoseconds if you are careful). And that means you don’t have idle WebAssembly modules hanging around consuming memory and processor space while waiting for inbound requests. Because Spin is fast, it can also be light on resources.
When you’re ready to see for yourself, Spin provides a simple spin up
command to locally run your code.
Fermyon currently only supports a top-level HTTP request/response model for a few languages. We’re adding more. But you don’t need to wait to use Spin to run AssemblyScript, Python, Ruby, Grain, or others. Spin ships with a 100% compatible Wagi implementation. As long as your chosen language supports the WASI specification for files and environment variables, you can use it to write Spin apps.
Not Just HTTP
For supported languages like Rust and Go, Spin supports more than just HTTP responders. Here’s an example that listens on a Redis channel:
use anyhow::Result;
use bytes::Bytes;
use spin_sdk::redis_component;
use std::str::from_utf8;
/// A simple Spin Redis component.
#[redis_component]
fn on_message(message: Bytes) -> Result<()> {
println!("{}", from_utf8(&message)?);
Ok(())
}
In this case, the Spin component listens for a message, and then prints the message. Every time a new message is pushed onto the relevant channel, the WebAssembly component is started, and the on_message
function is executed. Again, this whole process happens in milliseconds. Spin is fast!
HTTP and Redis are the first two responders for Spin, and more are on the way. Jump into the discussion on Discord or peruse the issue queue to see what else is in the works.
If you’re ready to dive in to some practical coding, you can walk through a tutorial on building a URL shortener with Spin.
Where is Fermyon Going with Spin?
Spin is our framework, and our execution environment. Already, it has some key features that we will make use of, including:
We are hard at work linking up to storage (like key/value, object storage, and RDBMS) as well as improved support for a variety of languages. And we are working closely with Bytecode Alliance to continue building standards and reference implementations.
Our goal is to build an excellent development platform for the next generation of microservices and web apps, achieving many of the goals that serverless computing has long pursued.
Getting Involved
As with the rest of Fermyon’s open source projects, Spin is licensed under the Apache 2 licenses. The source is hosted on GitHub. We’re happy to receive issues and PRs in the project. We’re working hard to make our documentation top-grade. If you have any trouble, please file an issue and help us improve. We want Spin to be easy!
If you’re interested in chatting, join the Fermyon Discord server. There’s a dedicated Spin channel, and you can also stay on top of other Fermyon news.
If you want to be the first to know what we’re up to, click the 👋 Talk to us button below or follow us on Twitter at @FermyonTech.