Building microservices in Rust with Spin

mangelosanto

Matt Angelosanto

Posted on May 18, 2023

Building microservices in Rust with Spin

Written by Oduah Chigozie✏️

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:

An overview of Spin

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.

What is a microservice?

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.

Installing Spin

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.

Installing on Windows

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
Enter fullscreen mode Exit fullscreen mode

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.

Installing on MacOS (Intel and Apple silicon)

To install the spin binary on MacOS, download the file with this command:

curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

The /usr/local/bin folder is a system path that houses executables that you can access from all directories in your system.

Installing on Linux

To install the binary, download the file with this command:

curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

Then, move the spin file to the /usr/local/bin folder with this command:

sudo mv spin /usr/local/bin/
Enter fullscreen mode Exit fullscreen mode

To verify the installation, run this command:

spin --help
Enter fullscreen mode Exit fullscreen mode

Building from source

To build the binary from source, follow these steps:

Clone the Spin repository:

git clone https://github.com/fermyon/spin
Enter fullscreen mode Exit fullscreen mode

Build the project:

cd spin && make build
Enter fullscreen mode Exit fullscreen mode

Verify the built binary:

./target/release/spin --help
Enter fullscreen mode Exit fullscreen mode

Installing with 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
Enter fullscreen mode Exit fullscreen mode

Open the spin directory:

cd spin
Enter fullscreen mode Exit fullscreen mode

Install the wasm32-wasi target for Rust:

rustup target add wasm32-wasi
Enter fullscreen mode Exit fullscreen mode

Compile and install the project to your system:

cargo install --locked --path .
Enter fullscreen mode Exit fullscreen mode

Verify a successful installation:

spin --help
Enter fullscreen mode Exit fullscreen mode

Setting up the project folder

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
Enter fullscreen mode Exit fullscreen mode

If no templates are installed on your system, run this command:

spin templates install --git https://github.com/fermyon/spin --update
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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.

Running the project

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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: The manifest file

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 <youremail@example.com>"]
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"
Enter fullscreen mode Exit fullscreen mode

From seeing the file, you’ll notice a few key things:

  • The 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 microservice
  • The source variable on the 10th line, which points to where the compiler places the compiled WebAssembly component
  • The route variable on the 13th line, which configures the route that the microservice lies. /… is a wildcard, it makes the microservice accessible from any route

Lib.rs: The main library for your microservice

lib.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()))?)
}
Enter fullscreen mode Exit fullscreen mode

In this file you’ll notice these key components: Line 8:

#[http_component]
Enter fullscreen mode Exit fullscreen mode

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()))?
    )
}
Enter fullscreen mode Exit fullscreen mode

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.

Building a functional microservice

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)
}
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

If you don’t do that, you’ll get an HttpError::DestinationNotAllowed error when you run the project.

Conclusion

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!


LogRocket: Full visibility into web frontends for Rust apps

Debugging Rust applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking performance of your Rust apps, automatically surfacing errors, and tracking slow network requests and load time, try LogRocket.

LogRocket Dashboard Free Trial Banner

LogRocket is like a DVR for web apps, recording literally everything that happens on your Rust app. 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.

💖 💪 🙅 🚩
mangelosanto
Matt Angelosanto

Posted on May 18, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related