Accessing external APIs from Spin applications
James Bohrman
Whether you are building a Discord bot with Spin or being a little more experimental, chances are you’ll probably want to have the ability to make outbound HTTP calls if you’re a Spin user.
Spin provides an extension that makes it simple to work with REST services. In this blog post, we’re going to show you how to make use of outbound HTTP calls to access external APIs using the wasi-experimental-http
crate in Rust.
Similar examples also exists in the SDKs for Go and AssemblyScript.
Adding networking to WASI
At it’s core, WebAssembly relies on the idea of an isolated and sandboxed environment that is separate from the host environment. WASI expands upon this by providing a modular interface that enables a set of systems APIs specific to WebAssembly. There is currently a proposed networking API that is under consideration, but until it is agreed upon and implemented, WASI does not have the ability to open outbound network sockets.
The Fermyon Solution
We are in favor of a stronger security stance on networking. We like the idea of providing a high-level HTTP library with a permissions-based capability wrapped around it. To illustrate, we’ve developed an experimental API that enables outbound HTTP requests which we’ll dive into in this section. The API is available in a variety of languages but for this post we’re going to be leveraging Rust. Let’s get started.
Clone the project repo
To get started, we’re going to need to clone a repo that has a variety of examples demonstrating various Spin HTTP components in different programming languages:
$ git clone https://github.com/fermyon/spin-kitchensink.git
If you want to learn more about a component, dive into the README
and navigate to the corresponding section. For this post, we’re going to be using the rust-outbound-http
component that enables us to send outbound HTTP requests with Rust:
cd rust-outbound-http
Set up the component
To use this component, we’re going to need to define the spin.toml
file which allows us to define the characteristics of our Spin component. Open the config file in your preferred text editor:
nano spin.toml
For this post, we’re going to be using the Dogs API to request information about various dog breeds via HTTP. To do this we’re going to need to add the domain of the API into the allowed_http_hosts
section of the component:
[[component]]
id = "rust-outbound-http"
source = "rust-outbound-http/target/wasm32-wasi/release/rust_outbound_http.wasm"
# set the service URL as an environment variable pointing to the previous component
environment = { SERVICE_URL = "https://api.thedogapi.com/v1/breeds/2" }
# add the domain of the service URL to the list of allowed hosts, so the component
# is allowed to send a request to it.
allowed_http_hosts = [ "https://api.thedogapi.com/" ]
You’ll also notice a field for SERVICE_URL
where we will have to add the path of the API request we are attempting to call. After we’ve saved our spin.toml
, we should be ready to build and deploy our component.
Building the component
We’re now ready to build the wasm
module that we will eventually be using in our Spin component. To do this, we’ll need to install the Rust package manager cargo
to build a release. You’ll need to make sure you install Rust so you can use Cargo’s features:
cargo build --release --target wasm32-wasi
We’re now ready to build the wasm
module that we will eventually be using in our Spin component. To do this, we’ll need to use cargo
to build a release:
cargo build -r --target wasm32-wasi
Once we have our module built, we should be ready to deploy with Spin.
Running and testing with Spin
Let’s go back and take another look at the source
definition in our spin.toml
file:
source = "rust-outbound-http/target/wasm32-wasi/release/rust_outbound_http.wasm"
Before we attempt to deploy with Spin, we need to make sure that our .wasm
binary is at the path we have defined in this field. If everything looks good, we should be able to run spin up
and be greeted with a response like this:
Serving HTTP on address http://127.0.0.1:3000
Now that our component is running, we’ll want to test it by cURLing localhost:3000
at the /outbound
route we defined in our `spin.toml:
curl -i localhost:3000/outbound
We should get a response that looks something like this:
{
"weight": {
"imperial": "50 - 60",
"metric": "23 - 27"
},
"height": {
"imperial": "25 - 27",
"metric": "64 - 69"
},
"id": 2,
"name": "Afghan Hound",
"country_code": "AG",
"bred_for": "Coursing and hunting",
"breed_group": "Hound",
"life_span": "10 - 13 years",
"temperament": "Aloof, Clownish, Dignified, Independent, Happy",
"origin": "Afghanistan, Iran, Pakistan",
"reference_image_id": "hMyT4CDXR"
}
Conclusion
The WebAssembly ecosystem is going through a massive shift as the community begins to embrace the idea of server-side Wasm having potential as the next phase in cloud-native computing. If you’re interested in joining a community of WebAssembly experts and enthusiasts, you should consider joining our Discord server! We have a variety of activities such as themed technical channels, exposure to subject matter experts, and interactive events for the community.
Join here!