Skip to content

Commit

Permalink
Merge pull request fermyon#1977 from lann/enhance-http-types
Browse files Browse the repository at this point in the history
rust: Add some convenience methods/impls to http types
  • Loading branch information
lann authored Oct 31, 2023
2 parents 0da5051 + 3821266 commit 561b3e1
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 93 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ edition = "2021"
crate-type = ["cdylib"]

[dependencies]
# Useful crate to handle errors.
anyhow = "1"
# Crate to simplify working with bytes.
http = "0.2"
# The Spin SDK.
spin-sdk = { path = "../../../sdk/rust" }
url = "2"

[workspace]
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
use anyhow::Result;
use spin_sdk::{
http::{IntoResponse, Request},
http::{IntoResponse, Request, Response},
http_component,
};

/// Send an HTTP request and return the response.
#[http_component]
async fn send_outbound(_req: Request) -> Result<impl IntoResponse> {
let mut res: http::Response<String> = spin_sdk::http::send(
http::Request::builder()
.method("GET")
.uri("/hello")
.body(())?,
)
.await?;
res.headers_mut()
.insert("spin-component", "rust-outbound-http".try_into()?);
println!("{:?}", res);
Ok(res)
let resp: Response = spin_sdk::http::send(Request::get("/hello")).await?;
let resp = resp
.into_builder()
.header("spin-component", "rust-outbound-http")
.build();
println!("{resp:?}");
Ok(resp)
}
1 change: 0 additions & 1 deletion examples/http-rust-outbound-http/outbound-http/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions examples/http-rust-outbound-http/outbound-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ edition = "2021"
crate-type = ["cdylib"]

[dependencies]
# Useful crate to handle errors.
anyhow = "1"
# General-purpose crate with common HTTP types.
http = "0.2"
# The Spin SDK.
spin-sdk = { path = "../../../sdk/rust" }

[workspace]
21 changes: 10 additions & 11 deletions examples/http-rust-outbound-http/outbound-http/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
use anyhow::Result;
use spin_sdk::{
http::{IntoResponse, Request},
http::{IntoResponse, Request, Response},
http_component,
};

/// Send an HTTP request and return the response.
#[http_component]
async fn send_outbound(_req: Request) -> Result<impl IntoResponse> {
let mut res: http::Response<String> = spin_sdk::http::send(
http::Request::builder()
.method("GET")
.uri("https://random-data-api.fermyon.app/animals/json")
.body(())?,
)
let resp: Response = spin_sdk::http::send(Request::get(
"https://random-data-api.fermyon.app/animals/json",
))
.await?;
res.headers_mut()
.insert("spin-component", "rust-outbound-http".try_into()?);
println!("{:?}", res);
Ok(res)
let resp = resp
.into_builder()
.header("spin-component", "rust-outbound-http")
.build();
println!("{resp:?}");
Ok(resp)
}
40 changes: 34 additions & 6 deletions sdk/rust/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub struct Request {
}

impl Request {
/// Create a new request from a method and uri
/// Creates a new request from a method and uri
pub fn new(method: Method, uri: impl Into<String>) -> Self {
Self {
method,
Expand All @@ -44,6 +44,23 @@ impl Request {
}
}

/// Creates a [`RequestBuilder`]
pub fn builder() -> RequestBuilder {
RequestBuilder::new(Method::Get, "/")
}

/// Creates a [`RequestBuilder`] to GET the given `uri`
pub fn get(uri: impl Into<String>) -> RequestBuilder {
RequestBuilder::new(Method::Get, uri)
}

/// Creates a [`RequestBuilder`] to POST the given `body` to `uri`
pub fn post(uri: impl Into<String>, body: impl conversions::IntoBody) -> RequestBuilder {
let mut builder = RequestBuilder::new(Method::Post, uri);
builder.body(body);
builder
}

/// The request method
pub fn method(&self) -> &Method {
&self.method
Expand Down Expand Up @@ -95,11 +112,6 @@ impl Request {
self.body
}

/// Create a request builder
pub fn builder() -> RequestBuilder {
RequestBuilder::new(Method::Get, "/")
}

fn parse_uri(uri: String) -> (Option<hyperium::Uri>, String) {
(
hyperium::Uri::try_from(&uri)
Expand Down Expand Up @@ -244,11 +256,27 @@ impl Response {
self.body
}

/// Converts this response into a [`ResponseBuilder`]. This can be used to
/// update a response before passing it on.
pub fn into_builder(self) -> ResponseBuilder {
ResponseBuilder { response: self }
}

fn builder() -> ResponseBuilder {
ResponseBuilder::new(200)
}
}

impl std::fmt::Debug for Response {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Response")
.field("status", &self.status)
.field("headers", &self.headers)
.field("body.len()", &self.body.len())
.finish()
}
}

/// A builder for `Response``
pub struct ResponseBuilder {
response: Response,
Expand Down
14 changes: 13 additions & 1 deletion sdk/rust/src/http/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use async_trait::async_trait;

use crate::wit::wasi::io::streams;

use super::{Headers, IncomingRequest, IncomingResponse, OutgoingRequest, OutgoingResponse};
use super::{
Headers, IncomingRequest, IncomingResponse, OutgoingRequest, OutgoingResponse, RequestBuilder,
};

use super::{responses, NonUtf8BodyError, Request, Response};

Expand Down Expand Up @@ -528,6 +530,16 @@ impl TryIntoOutgoingRequest for Request {
}
}

impl TryIntoOutgoingRequest for RequestBuilder {
type Error = std::convert::Infallible;

fn try_into_outgoing_request(
mut self,
) -> Result<(OutgoingRequest, Option<Vec<u8>>), Self::Error> {
self.build().try_into_outgoing_request()
}
}

#[cfg(feature = "http")]
impl<B> TryIntoOutgoingRequest for hyperium::Request<B>
where
Expand Down

0 comments on commit 561b3e1

Please sign in to comment.