Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update readme to latest template syntax #2178

Merged
merged 10 commits into from
Dec 20, 2023
117 changes: 72 additions & 45 deletions sdk/rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,107 @@

The Spin Rust SDK makes it easy to build Spin components in Rust.

tpmccallum marked this conversation as resolved.
Show resolved Hide resolved
### Writing Spin HTTP components in Rust
### Writing Spin HTTP Components in Rust

This library simplifies writing Spin HTTP components. Below is an example of
such a component:

```rust
// lib.rs
use anyhow::Result;
use spin_sdk::{
http::{Request, Response},
http_component,
};
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;

/// A simple Spin HTTP component.
#[http_component]
fn hello_world(req: Request) -> Result<Response> {
println!("{:?}", req.headers);
Ok(Response::new_with_headers(200, &[] "Hello, Fermyon!"))
fn handle_hello_world(req: Request) -> anyhow::Result<impl IntoResponse> {
println!("Handling request to {:?}", req.header("spin-full-url"));
Ok(Response::builder()
.status(200)
.header("content-type", "text/plain")
.body("Hello, Fermyon")
.build())
}
```

The important things to note in the function above:
The important things to note about the function above are:

- the `spin_sdk::http_component` macro — this marks the function as the
entrypoint for the Spin component
- the function signature — `fn hello_world(req: Request) -> Result<Response>` —
`req` can be any number of types including the built in `Request` type or
the `http::Request` from the popular `http` crate. Likewise, the response type
can be many things including the built in `Response` type or the `http::Response` type
from the `http` crate.
- the `spin_sdk::http_component` macro marks the function as the entry point for the Spin component,
- in the function signature (`fn handle_hello_world(req: Request) -> anyhow::Result<impl IntoResponse>`), `req` can be any number of types, including the built-in `Request` type or the `http::Request` from the popular `http` crate
tpmccallum marked this conversation as resolved.
Show resolved Hide resolved
- in the function signature, the response type can be many things, including `anyhow::Result<impl IntoResponse>` (as shown above) or the `http::Response` type from the `http` crate (e.g. `Result<Response>`). Note - Using the `http` crate will require you to add it, e.g. `cargo install http`.
tpmccallum marked this conversation as resolved.
Show resolved Hide resolved

### Making outbound HTTP requests
### Making Outbound HTTP Requests
tpmccallum marked this conversation as resolved.
Show resolved Hide resolved

Let's see an example where the component makes an outbound HTTP request to a
server, modifies the result, then returns it:
Let's see an example where the component makes an outbound HTTP request to a server, modifies the result, and then returns it:

```rust
use anyhow::Result;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't import anyhow::Result in the example above so I would remove this and change line 45 to:

async fn handle_hello_world(_req: Request) -> anyhow::Result<impl IntoResponse> {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

tpmccallum marked this conversation as resolved.
Show resolved Hide resolved
use spin_sdk::{
http::{IntoResponse, Request, Method, Response},
http_component,
};

#[http_component]
async fn hello_world(_req: Request) -> Result<Response> {
let mut res: http::Response<String> = spin_sdk::http::send(
http::Request::builder()
.method("GET")
.uri("https://fermyon.com")
.body(())?,
).await?;
async fn handle_hello_world(_req: Request) -> Result<impl IntoResponse> {
// Create the outbound request object
let req = Request::builder()
.method(Method::Get)
.uri("https://random-data-api.fermyon.app/animals/json")
.build();

res.headers_mut()
.insert(http::header::SERVER, "spin/0.1.0".try_into()?);
// Send the request and await the response
let res: Response = spin_sdk::http::send(req).await?;

println!("{:?}", res); // log the response
Ok(res)
}

```

In order for the component above to be allowed to make the outbound HTTP
request, the destination host must be declared in the Spin application
configuration:
For the component above to be allowed to make the outbound HTTP request, the destination host must be declared, using the `allowed_outbound_hosts` configuration, in the Spin application's manifest (the `spin.toml` file):

```toml
[[component]]
id = "hello"
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
allowed_outbound_hosts = [ "https://fermyon.com" ]
[component.trigger]
route = "/hello"
spin_manifest_version = 2

[application]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <your-name@example.com>"]
description = "An example application"

[[trigger.http]]
route = "/..."
component = "hello-world"

[component.hello-world]
source = "target/wasm32-wasi/release/hello_world.wasm"
allowed_outbound_hosts = ["https://random-data-api.fermyon.app"]
[component.hello-world.build]
command = "cargo build --target wasm32-wasi --release"
watch = ["src/**/*.rs", "Cargo.toml"]
```

Making a request to this component, we can see the appended header, and that the
response contains the expected body:
## Building and Running the Spin Application
tpmccallum marked this conversation as resolved.
Show resolved Hide resolved

Spin build can be used to build all components defined in the Spin manifest file at the same time, and also has a flag that starts the application after finishing the compilation, `spin build --up`:
tpmccallum marked this conversation as resolved.
Show resolved Hide resolved

```bash
$ spin build --up
Building component hello-world with `cargo build --target wasm32-wasi --release`
Finished release [optimized] target(s) in 0.12s
Finished building all Spin components
Logging component stdio to ".spin/logs/"

Serving http://127.0.0.1:3000
Available Routes:
hello-world: http://127.0.0.1:3000 (wildcard)
```
$ curl -I localhost:3000/hello

Once our application is running, we can make a request (by visiting `http://localhost:3000/` in a web browser) or using `curl` as shown below:

```bash
$ curl -i localhost:3000
HTTP/1.1 200 OK
content-length: 29350
content-type: text/html; charset=utf-8
server: spin/0.1.0
content-length: 77
content-type: application/json

{"timestamp":1702599575198,"fact":"Sharks lay the biggest eggs in the world"}
```
tpmccallum marked this conversation as resolved.
Show resolved Hide resolved
Loading