In the previous sections, we have deployed existing WebAssembly (Wasm) applications to our Kubernetes cluster. Let's explore how to build our own using Spin, an open source developer tool for building and running serverless applications with WebAssembly.
This document assumes you have followed the setup guide and have an environment configured with the Spin CLI and other language-specific tools (such as node
, cargo
, or tinygo
).
$ spin --version
spin 1.1.0
Spin is an open source framework for building, distributing, and running serverless applications and microservices with WebAssembly (or Wasm).
Spin uses Wasm because of its portability, sandboxed execution environment, and near-native speed. More and more languages have support for WebAssembly, so you should be able to use your favorite language to build your first serverless application with Wasm.
The following two sections will guide you through creating your first Spin applications. Before getting started, make sure you have configured the correct Spin templates. Here are a few of the templates we will use:
$ spin templates list
+-----------------------------------------------------------------------------+
| Name Description |
+=============================================================================+
| http-empty HTTP application with no components |
| http-js HTTP request handler using Javascript |
| http-rust HTTP request handler using Rust |
| http-ts HTTP request handler using Typescript |
| kv-explorer Explore the contents of Spin KV stores |
| nextjs-frontend Build your front-end application using Next.js and Spin |
| static-fileserver Serves static files from an asset directory |
+-----------------------------------------------------------------------------+
You are now ready to create your first Spin applications. Depending on what language you are familiar with, you can choose to follow the rest of the guide in Rust or JavaScript/TypeScript.
Rust has excellent support for WebAssembly, and Spin has an SDK for Rust that simplifies building Spin applications in Rust.
Note: find more about building Spin applications in Rust from the Spin documentation.
You can create a new Spin application in Rust based on a template — in this case, based on the HTTP Rust template for Spin. This will create all the required configuration and files for your application — in this case, a regular Rust library project, with an additional configuration file, spin.toml
:
$ spin new http-rust hello-rust --accept-defaults && cd hello-rust
$ tree
|-- Cargo.toml
|-- spin.toml
-- src
-- lib.rs
Let's explore the spin.toml
file. This is the Spin manifest file, which tells Spin what events should trigger what components. In this case our trigger is HTTP, for a web application, and we have only one component, at the route /...
— a wildcard that matches any request sent to this application. In more complex applications, you can define multiple components that are triggered for requests on different routes.
spin_manifest_version = "1"
name = "hello-rust"
# This is an HTTP application.
trigger = { type = "http", base = "/" }
version = "0.1.0"
[[component]]
id = "hello-rust"
# The Wasm module to execute for this component.
source = "target/wasm32-wasi/release/hello_rust.wasm"
# This component is not allowed to make any outbound HTTP requests.
allowed_http_hosts = []
[component.trigger]
# This component will get invoked for all requests to `/...`.
route = "/..."
[component.build]
# The command to execute when running `spin build`.
command = "cargo build --target wasm32-wasi --release"
Note: you can learn more about the Spin manifest file in the Spin documentation.
You are now ready to build your application using spin build
, which will invoke each component's [component.build.command]
from spin.toml
:
$ spin build
Executing the build command for component hello-rust: cargo build --target wasm32-wasi --release
...
Successfully ran the build command for the Spin components.
Note: if you are having issues building your application, refer to the troubleshooting guide from the setup document.
You can now start your application using spin up
:
$ spin up
Serving http://127.0.0.1:3000
Available Routes:
hello-rust: http://127.0.0.1:3000 (wildcard)
The command will start Spin on port 3000. You can now access the application by navigating to localhost:3000
in your browser, or by using curl
:
$ curl localhost:3000
Hello, Fermyon
That response is coming from the handler function for this component — in the case of a Rust component, defined in src/lib.rs
. Our entire application consists of a single Rust function, handle_hello_rust
, which takes the HTTP request as an argument and returns an HTTP response.
Let's change the message body to "Hello, WebAssembly!":
// The entrypoint to our component.
#[http_component]
fn handle_hello_rust(req: Request) -> Result<Response> {
println!("{:?}", req.headers());
Ok(http::Response::builder()
.status(200)
.header("foo", "bar")
// Change this message from "Hello, Fermyon" to "Hello, WebAssembly!".
.body(Some("Hello, WebAssembly!".into()))?)
}
We can now run spin build
again, which will compile our component, and we can use the --up
flag to automatically start the application, then send another request:
$ spin build --up
$ curl -v localhost:3000
< HTTP/1.1 200 OK
< foo: bar
< content-length: 19
Hello, WebAssembly!
You are now ready to expand your application. You can follow the guide for building Rust components from the Spin documentation.
Note: you can find the complete applications used in this workshop in the
apps
directory.
JavaScript is one of the most popular programming languages. Spin has an experimental SDK and toolchain for JavaScript and TypeScript which is based on QuickJS, a small embeddable JavaScript runtime.
Note: you can read more about how the Spin SDK for JavaScript and TypeScript is built on Fermyon's blog.
Let's create a new Spin application in TypeScript, based on the HTTP template. This will create all the required configuration and files for the application:
$ spin new http-ts hello-typescript --accept-defaults && cd hello-typescript
$ tree
|-- README.md
|-- package.json
|-- spin.toml
|-- src
| -- index.ts
|-- tsconfig.json
|-- webpack.config.js
Let's explore the spin.toml
file. This is the Spin manifest file, which tells Spin what events should trigger what components. In this case our trigger is HTTP, for a web application, and we have only one component, at the route /...
— a wildcard that matches any request sent to this application. In more complex applications, you can define multiple components that are triggered for requests on different routes.
spin_manifest_version = "1"
name = "hello-typescript"
# This is an HTTP application.
trigger = { type = "http", base = "/" }
version = "0.1.0"
[[component]]
id = "hello-typescript"
# The Wasm module to execute for this component.
source = "target/spin-http-js.wasm"
exclude_files = ["**/node_modules"]
[component.trigger]
# This component will get invoked for all requests to `/...`.
route = "/..."
[component.build]
# The command to execute when running `spin build`.
command = "npm run build"
Note: you can learn more about the Spin manifest file in the Spin documentation.
First install the dependencies for the template with npm install
. You are now ready to build your application using spin build
, which will invoke each component's [component.build.command]
from spin.toml
:
$ npm install
$ spin build
Executing the build command for component hello-typescript: npm run build
...
Spin compatible module built successfully
Successfully ran the build command for the Spin components.
Note: if you are having issues building your application, refer to the troubleshooting guide from the setup document.
You can now start your application using spin up
:
$ spin up
Serving http://127.0.0.1:3000
Available Routes:
hello-typescript: http://127.0.0.1:3000 (wildcard)
The command will start Spin on port 3000. You can now access the application by navigating to localhost:3000
in your browser, or by using curl
:
$ curl localhost:3000
Hello, from TS-SDK
That response is coming from the handler function for this component — in the case of a TypeScript component, defined in the index file from src/index.ts
. Our entire application consists of a single function, handleRequest
, which takes the HTTP request as an argument and returns an HTTP response.
Let's change the message body to "Hello, WebAssembly!":
export async function handleRequest(request: HttpRequest): Promise<HttpResponse> {
return {
status: 200,
headers: { "foo": "bar" },
body: "Hello, WebAssembly!"
}
}
We can now run spin build
again, which will compile our component, and we can use the --up
flag to automatically start the application, then send another request:
$ spin build --up
$ curl -v localhost:3000
< HTTP/1.1 200 OK
< foo: bar
< content-length: 19
Hello, WebAssembly!
You are now ready to expand your application. You can follow the guide for building JavaScript components from the Spin documentation.
Note: you can find the complete applications used in this workshop in the
apps
directory.
In this section you learned how to:
- Check your Spin CLI version
- Create a new Spin app using a template
- Build your Spin application with
spin build
- Run your application locally with
spin up
- Modify an HTTP trigger's route and entrypoint
- Go back to 0. Setup if you still have questions on previous section
- Otherwise, proceed to 2. Run your first wasm app on k3d if you still have questions on previous section.
- (optionally) If finished, let us know what you thought of the Spin and the workshop with this short Typeform survey.