Skip to content

Commit

Permalink
Merge pull request #961 from itowlson/http-in-v2-again
Browse files Browse the repository at this point in the history
Update Rust HTTP to latest SDK
  • Loading branch information
itowlson authored Oct 29, 2023
2 parents fc79f74 + 065cd21 commit 3b3a9d2
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 16 deletions.
28 changes: 15 additions & 13 deletions content/spin/v2/http-trigger.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ The exact signature of the HTTP handler, and how a function is identified to be

{{ startTab "Rust"}}

In Rust, the handler is identified by the `#[spin_sdk::http_component]` attribute. The handler function can have one of two forms: _request-response_ or _input-output parameter_.
In Rust, the handler is identified by the [`#[spin_sdk::http_component]`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/attr.http_component.html) attribute. The handler function can have one of two forms: _request-response_ or _input-output parameter_.

**Request-Response Handlers**

Expand All @@ -156,14 +156,16 @@ In this form, nothing is sent to the client until the entire response is ready.

You have some flexibility in choosing the types of the request and response. The request may be:

* `http::Request`
* `spin_sdk::http::IncomingRequest`
* Any type for which you have implemented the `spin_sdk::http::conversions::TryFromIncomingRequest` trait
* [`http::Request`](https://docs.rs/http/latest/http/request/struct.Request.html)
* [`spin_sdk::http::Request`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/struct.Request.html)
* [`spin_sdk::http::IncomingRequest`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/struct.IncomingRequest.html)
* Any type for which you have implemented the [`spin_sdk::http::conversions::TryFromIncomingRequest`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/conversions/trait.TryFromIncomingRequest.html) trait

The response may be:

* `http::Response`
* Any type for which you have implemented the `spin_sdk::http::IntoResponse` trait
* [`http::Response`](https://docs.rs/http/latest/http/response/struct.Response.html) - typically constructed via `Response::builder()`
* [`spin_sdk::http::Response`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/struct.Response.html) - typically constructed via a [`ResponseBuilder`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/struct.ResponseBuilder.html)
* Any type for which you have implemented the [`spin_sdk::http::IntoResponse`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/trait.IntoResponse.html) trait
* A `Result` where the success type is one of the above and the error type is `anyhow::Error` or another error type for which you have implemented `spin_sdk::http::IntoResponse` (such as `anyhow::Result<http::Response>`)

For example:
Expand All @@ -189,20 +191,20 @@ To extract data from the request, specify a body type as the generic parameter f

**Input-Output Parameter Handlers**

In this form, the handler function receives the request as an argument of type `spin_sdk::http::IncomingRequest`. It also receives an argument of type `spin_sdk::http::ResponseOutparam`, through which is sends the response. The function does not return a value. This form is recommended for streaming responses.
In this form, the handler function receives the request as an argument of type [`spin_sdk::http::IncomingRequest`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/struct.IncomingRequest.html). It also receives an argument of type [`spin_sdk::http::ResponseOutparam`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/struct.ResponseOutparam.html), through which is sends the response. The function does not return a value. This form is recommended for streaming responses.

To send a response:

1. Create a `spin_sdk::http::OutgoingResponse`.
2. Call `take_body()` on the `OutgoingResponse` - this gives you a `Sink` that you can later use to send data via the response.
3. Call `ResponseOutparam::set`, passing the response argument and an `Ok` of the `OutgoingResponse`.
1. Create a [`spin_sdk::http::OutgoingResponse`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/struct.OutgoingResponse.html).
2. Call `take_body()` on the `OutgoingResponse` - this gives you a [`futures::Sink`](https://docs.rs/futures/latest/futures/sink/trait.Sink.html) that you can later use to send data via the response.
3. Call `set` on the `ResponseOutparam`, passing the `OutgoingResponse`.
4. Call `send` on the `Sink` as many times as you like. Each send is carried out as you call it, so you can send the first part of the response without waiting for the whole response to be ready.

> You will need to reference the `futures` crate in `Cargo.toml`, and `use futures::SinkExt;`, to access the `send` method.
```rust
use futures::SinkExt;
use spin_sdk::http::{Fields, IncomingRequest, OutgoingResponse, ResponseOutparam};
use spin_sdk::http::{Headers, IncomingRequest, OutgoingResponse, ResponseOutparam};
use spin_sdk::http_component;

/// A streaming Spin HTTP component.
Expand All @@ -211,13 +213,13 @@ async fn handle_hello_rust(_req: IncomingRequest, response_out: ResponseOutparam
// Status code and headers must be supplied before calling take_body
let response = OutgoingResponse::new(
200,
&Fields::new(&[("content-type".to_string(), b"text/plain".to_vec())]),
&Headers::new(&[("content-type".to_string(), b"text/plain".to_vec())]),
);
// Get the sink for writing the body into. This must be mutable!
let mut body = response.take_body();

// Connect the OutgoingResponse to the ResponseOutparam.
ResponseOutparam::set(response_out, Ok(response));
response_out.set(response);

// Write to the body sink over a period of time. (In this case we simulate a
// long-running operation by manually calling `thread::sleep`.)
Expand Down
6 changes: 3 additions & 3 deletions content/spin/v2/rust-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ for writing Spin components with the Spin Rust SDK.
> Make sure to read [the page describing the HTTP trigger](./http-trigger.md) for more
> details about building HTTP applications.
Building a Spin HTTP component using the Rust SDK means writing a single function decorated with the `#[http_component]` attribute. The function can have one of two forms:
Building a Spin HTTP component using the Rust SDK means writing a single function decorated with the [`#[http_component]`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/attr.http_component.html) attribute. The function can have one of two forms:

* takes an HTTP request as a parameter, and returns an HTTP response — shown below
* taken as parameters _both_ the HTTP request and an object through which to write a response - see [the HTTP trigger page](./http-trigger#authoring-http-components) for an example.
Expand All @@ -103,10 +103,10 @@ async fn handle_hello_rust(_req: Request<()>) -> anyhow::Result<impl IntoRespons

The important things to note in the implementation above:

- the `spin_sdk::http_component` macro marks the function as the entry point for the Spin component
- the [`spin_sdk::http_component`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/attr.http_component.html) macro marks the function as the entry point for the Spin component
- the function signature — `fn hello_world(req: Request) -> Result<impl IntoResponse>`
the Spin HTTP component uses the HTTP objects from the popular Rust crate
[`http`](https://crates.io/crates/http), and allows a flexible set of response types via the `IntoResponse` trait
[`http`](https://crates.io/crates/http), and allows a flexible set of response types via the[ `IntoResponse`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/trait.IntoResponse.html) trait

> If you're familiar with Spin 1.x, you will see some changes when upgrading to the Spin 2 SDK. Mostly these provide more flexibility, but you will likely need to change some details such as module paths. If you don't want to modify your code, you can continue using the 1.x SDK - your components will still run.
Expand Down

0 comments on commit 3b3a9d2

Please sign in to comment.