Rust offers a powerful and efficient approach to developing applications. And with Spin, building powerful microservices for distributed applications has gotten so much easier. The performance benefits of Rust with the ease-of-use and scalability of Spin makes them a valuable choice for developers seeking to build reliable and scalable systems.
This article will give you an overview of the Spin framework and walk you through building a simple microservice.
Jump ahead:
Spin is an open source framework for developing, running, and deploying microservices and web applications. You can develop any microservice application in Spin with any wasi-compatible languages, such as Go, Rust, Java, and JavaScript.
Spin converts your microservice applications into WebAssembly components for serverless cloud platforms, like AWS lambda, a self-hosted server on your system, or WebAssembly cloud platforms, like Fermyon Cloud. When it comes to building and running microservices, WebAssembly provides security, portability, and speed.
Microservices are independent software components that perform a specific function within a larger distributed application. They are designed to work together in a distributed system, with each service responsible for a single task, while communicating with other services to carry out complex operations.
Microservices are built to be small, lightweight, modular, and independently deployable. You can deploy them in containers, such as Docker, and manage them using container orchestration tools, like Kubernetes. You can also implement them using serverless computing platforms, like Google Cloud functions, and AWS lambda.
Now that you are familiar with Spin and microservices, It’s time to install the spin
binary into your system. This section will walk you through installing the binary file.
The binary file allows you to set up a project, and host a local server, and runs on all major operating systems, including Windows, Linux, and MacOS. You also have the option to build the binary from its source code, or install it into your system with cargo
.
To install the binary file on Windows, download the Windows binary release, unzip the file, and place the spin.exe
file in your system path.
To verify the installation, run this in your command prompt:
>spin --help
If you get an error, try to reopen the command prompt, or reboot your system. If you don’t get an error, congratulations! You just installed the binary on your system, and you can begin setting up the project folder.
To install the spin
binary on MacOS, download the file with this command:
curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash
The command above downloads the compatible binary file for your system. To allow easy access to the binary from any directory on your system, move the spin
file to the /usr/local/bin
folder with this command:
sudo mv spin /usr/local/bin/
The /usr/local/bin
folder is a system path that houses executables that you can access from all directories in your system.
To install the binary, download the file with this command:
curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash
Then, move the spin
file to the /usr/local/bin
folder with this command:
sudo mv spin /usr/local/bin/
To verify the installation, run this command:
spin --help
To build the binary from source, follow these steps:
Clone the Spin repository:
git clone https://github.com/fermyon/spin
Build the project:
cd spin && make build
Verify the built binary:
./target/release/spin --help
cargo
To install the binary with cargo
, follow these steps:
Clone the Spin repository:
git clone https://github.com/fermyon/spin -b v0.9.0
Open the spin
directory:
cd spin
Install the wasm32-wasi
target for Rust:
rustup target add wasm32-wasi
Compile and install the project to your system:
cargo install --locked --path .
Verify a successful installation:
spin --help
With spin
installed on your system, let’s set up a project folder for building a microservice. By the end of this section, you’ll have an initialized project folder for building your microservice.
Spin provides templates for building several different types of applications. To check the templates installed on your system, run this command:
spin templates list
If no templates are installed on your system, run this command:
spin templates install --git https://github.com/fermyon/spin --update
The command above installs all available templates in the Spin GitHub repo. After installing the templates, you can recheck the list to see the installed templates.
After installing the templates, run this command to begin setting up the project:
$ spin new Pick a template to start your application with: > http-c (HTTP request handler using C and the Zig toolchain) http-empty (HTTP application with no components) http-go (HTTP request handler using (Tiny)Go) http-grain (HTTP request handler using Grain) http-php (HTTP request handler using PHP) http-rust (HTTP request handler using Rust) http-swift (HTTP request handler using SwiftWasm) http-zig (HTTP request handler using Zig) redirect (Redirects a HTTP route) redis-go (Redis message handler using (Tiny)Go) redis-rust (Redis message handler using Rust) static-fileserver (Serves static files from an asset directory)
The command prompts you for the template you want to use, a name for the project, a description of the project, an HTTP path, and an HTTP base. For the template, select http-rust
. For the project name, write any name you want. For description, HTTP path, and HTTP base, you can hit Enter
to use their defaults.
After setting up the project, you might want to see how the application runs. This section shows you how to build, run, and test the project. By the end of the section, you’ll have the project running on your system.
After building the project, Spin generates a WebAssembly component from the source code. To build the application, you need to install the wasm32-wasi
target. You can install the wasm32-wasi
target, and compile the project into a WebAssembly component with these two commands:
rustup target add wasm32-wasi # Install the WebAssembly target spin build # Build the project
Once the commands are done, the generated WebAssembly component lies in the target/wasm32-wasi/release
folder. spin
lets you host the WebAssembly component on your system with this command:
spin up
It hosts the microservice application in http://localhost:3000/. Once the project is running, you can test it with the curl
command:
$ curl -i localhost:3000 HTTP/1.1 200 OK foo: bar content-length: 14 date: Wed, 01 Mar 2023 11:11:57 GMT Hello, Fermyon
Now that you’ve seen the project in action, It’s good to know how it works. In the following sections, we will walk through the key components of the spin.toml
, and the lib.rs
files in your project.
spin.toml
is a manifest file. It contains the configurations for your project. Take a look at the project’s spin.toml
file:
spin_version = "1" authors = ["Username <[email protected]>"] description = "" name = "project-name" trigger = { type = "http", base = "/" } version = "0.1.0" [[component]] id = "project-name" source = "target/wasm32-wasi/release/spin_test.wasm" allowed_http_hosts = [] [component.trigger] route = "/..." [component.build] command = "cargo build --target wasm32-wasi --release"
From seeing the file, you’ll notice a few key things:
trigger
variable on the 5th line, which configures the nature of the microservice. This microservice provides an HTTP interface for external applications to interact with the microservicesource
variable on the 10th line, which points to where the compiler places the compiled WebAssembly componentroute
variable on the 13th line, which configures the route that the microservice lies. /…
is a wildcard, it makes the microservice accessible from any routelib.rs
is the main library for your microservice. The compiler compiles this file into the WebAssembly component. Take a look at the project’s lib.rs
:
use anyhow::Result; use spin_sdk::{ http::{Request, Response}, http_component, }; /// A simple Spin HTTP component. #[http_component] fn handle_spin_test(req: Request) -> Result<Response> { println!("{:?}", req.headers()); Ok(http::Response::builder() .status(200) .header("foo", "bar") .body(Some("Hello, Fermyon".into()))?) }
In this file you’ll notice these key components:
Line 8:
#[http_component]
The http_component
macro signifies that the handle_spin_test
function is an HTTP component.
Line 9 – 15:
fn handle_spin_test(req: Request) -> Result<Response> { println!("{:?}", req.headers()); Ok( http::Response::builder() .status(200) .header("foo", "bar") .body(Some("Hello, Fermyon".into()))? ) }
Spin runs the handle_spin_test
function whenever you send an HTTP request to the microservice. The microservice returns the result of handle_spin_test
at the end of the request.
The initialized project only handles the basics of a Spin microservice. In this section, we will build a more functional microservice. The microservice that you will build by the end of this article is a cat facts generator. The microservices uses the cat fact ninja API to generate random cat facts.
To begin, initialize a project, and write this code into your lib.rs
:
use anyhow::Result; use spin_sdk::{ http::{Request, Response}, http_component, }; #[http_component] fn cat_facts(_req: Request) -> Result<Response> { // fetch fact from the API let mut res = spin_sdk::http::send( http::Request::builder() .method("GET") .uri("https://catfact.ninja/fact") .body(None)?, )?; // Add "Server" key into the header res.headers_mut() .insert(http::header::SERVER, "spin/0.1.0".try_into()?); // Send response to the client Ok(res) }
The spin
library provides methods for sending HTTP requests. In this microservice, we use that method to fetch cat facts from the cat fact ninja API. The method produces a response that the cat_facts
function can return as the microservice’s response object.
To finish up the project, add catfact.ninja
to the allowed_http_hosts
variable on the 11th line of the spin.toml
file:
allowed_http_hosts = ["catfact.ninja"]
If you don’t do that, you’ll get an HttpError::DestinationNotAllowed
error when you run the project.
Microservices are the foundation for distributed applications. They are independent pieces that interact with each other to form a larger distributed application. This article walks you through building microservices.
Using the knowledge in this article, you can build more complex microservices, like one that does database interactions, or authentications. To learn more about the Spin framework, be sure to check out the Spin documentation.
Thanks for reading!
Debugging Rust applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking the performance of your Rust apps, automatically surfacing errors, and tracking slow network requests and load time, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Rust application. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.
Modernize how you debug your Rust apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowSOLID principles help us keep code flexible. In this article, we’ll examine all of those principles and their implementation using JavaScript.
JavaScript’s Date API has many limitations. Explore alternative libraries like Moment.js, date-fns, and the new Temporal API.
Explore use cases for using npm vs. npx such as long-term dependency management or temporary tasks and running packages on the fly.
Validating and auditing AI-generated code reduces code errors and ensures that code is compliant.
One Reply to "Building microservices in Rust with Spin"
Please, can you update tutorial’s last chapter “cat ninja”?
I got compile error:
let mut res = spin_sdk::http::send(
| ___________________^
9 | | http::Request::builder()
10 | | .method(“GET”)
11 | | .uri(“https://catfact.ninja/fact”)
12 | | .body(None)?,
13 | | )?;
| |______^ the `?` operator cannot be applied to type `impl Future<Output = Result>`