Building microservices in Rust with Spin
Tags: rust, webdev
Published: 2023-05-18 15:01:39

**Written by [Oduah Chigozie](https://blog.logrocket.com/author/oduahchigozie/)✏️**

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](#overview-spin)
*   [What is a microservice?](#what-microservice)
*   [Installing Spin](#installing-spin)
*   [Setting up the project folder](#setting-up-project-folder)
*   [Running the project](#running-project)
*   [Spin.toml: The manifest file](#spin-toml-manifest-file)
*   [Lib.rs: The main library for your microservice](#libs-rs-main-library)
*   [Building a functional microservice](#building-functional-microservice)

## An overview of Spin <a name="overview-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](https://www.fermyon.dev/). When it comes to building and running microservices, WebAssembly provides security, portability, and speed.

## What is a microservice? <a name="what-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 <a name="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](https://github.com/fermyon/spin/releases/tag/v0.9.0), unzip the file, and place the `spin.exe` file in your system path. 

To verify the installation, run this in your command prompt:

```rust
>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](#heading=h.iqs73fxevzle).

### Installing on MacOS (Intel and Apple silicon)

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

```rust
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:

```rust
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.

### Installing on Linux

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

```rust
curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash
```

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

```rust
sudo mv spin /usr/local/bin/
```

To verify the installation, run this command:

```rust
spin --help
```

### Building from source

To build the binary from source, follow these steps: 

Clone the Spin repository:

```rust
git clone https://github.com/fermyon/spin
```

Build the project:

```rust
cd spin && make build
```

Verify the built binary:

```rust
./target/release/spin --help
```

### Installing with `cargo`

To install the binary with `cargo`, follow these steps: 

Clone the Spin repository:

```rust
git clone https://github.com/fermyon/spin -b v0.9.0
```

Open the `spin` directory:

```rust
cd spin
```

Install the `wasm32-wasi` target for Rust:

```rust
rustup target add wasm32-wasi
```

Compile and install the project to your system:

```rust
cargo install --locked --path .
```

Verify a successful installation:

```rust
spin --help
```

## Setting up the project folder <a name="setting-up-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:

```rust
spin templates list
```

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

```rust
spin templates install --git https://github.com/fermyon/spin --update
```

The command above installs all available templates in the [Spin GitHub repo](https://github.com/fermyon/spin). 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:

```rust
$ 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.

## Running the project <a name="running-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:

```rust
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:

```rust
spin up
```

It hosts the microservice application in [http://localhost:3000/](http://localhost:3000/hello). Once the project is running, you can test it with the `curl` command:

```rust
$ 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: The manifest file <a name="spin-toml-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:

```rust
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"
```

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 <a name="libs-rs-main-library">

`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`:

```rust
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:

```rust
#[http_component]
```

The `http_component` macro signifies that the `handle_spin_test` function is an HTTP component. Line 9 - 15:

```rust
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.

## Building a functional microservice <a name="building-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](https://catfact.ninja) to generate random cat facts. To begin, [initialize a project](#heading=h.iqs73fxevzle), and write this code into your `lib.rs`:

```rust
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:

```rust
allowed_http_hosts = ["catfact.ninja"]
```

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](https://developer.fermyon.com/spin/index). 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](https://lp.logrocket.com/blg/signup). 

[![LogRocket Dashboard Free Trial Banner](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://lp.logrocket.com/blg/signup)

[LogRocket](https://logrocket.com/signup) 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](https://lp.logrocket.com/blg/signup).