Skip to content

Commit fb4fda6

Browse files
committed
Add examples to rustdoc
Signed-off-by: itowlson <[email protected]>
1 parent 6ee0933 commit fb4fda6

File tree

6 files changed

+542
-16
lines changed

6 files changed

+542
-16
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ jobs:
3939
shell: bash
4040
run: cargo test --workspace
4141

42+
- name: Validate docs examples
43+
shell: bash
44+
run: cargo test --doc

src/http.rs

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,88 @@ use spin_executor::bindings::wasi::io::streams::{self, StreamError};
1818

1919
/// A unified request object that can represent both incoming and outgoing requests.
2020
///
21-
/// This should be used in favor of `IncomingRequest` and `OutgoingRequest` when there
21+
/// This should be used in favor of [IncomingRequest] and [OutgoingRequest] when there
2222
/// is no need for streaming bodies.
23+
///
24+
/// # Examples
25+
///
26+
/// Read the method, a header, and the body an incoming HTTP request, without streaming.
27+
///
28+
/// ```ignore
29+
/// use spin_sdk::http::{Method, Request, Response};
30+
/// use spin_sdk::http_component;
31+
///
32+
/// #[http_component]
33+
/// fn handle_request(req: Request) -> anyhow::Result<Response> {
34+
/// let method = req.method();
35+
/// let content_type = req.header("content-type");
36+
/// if *method == Method::Post {
37+
/// let body = String::from_utf8_lossy(req.body());
38+
/// }
39+
/// todo!()
40+
/// }
41+
/// ```
42+
///
43+
/// Send an outgoing GET request (no body) to `example.com`.
44+
///
45+
/// ```no_run
46+
/// use spin_sdk::http::{Request, Response};
47+
///
48+
/// # #[tokio::main]
49+
/// # async fn main() -> anyhow::Result<()> {
50+
/// let request = Request::get("example.com");
51+
/// let response: Response = spin_sdk::http::send(request).await?;
52+
/// # Ok(())
53+
/// # }
54+
/// ```
55+
///
56+
/// Send an outgoing POST request with a non-streaming body to `example.com`.
57+
///
58+
/// ```no_run
59+
/// use spin_sdk::http::{Request, Response};
60+
///
61+
/// # #[tokio::main]
62+
/// # async fn main() -> anyhow::Result<()> {
63+
/// let request = Request::post("example.com", "it's a-me, Spin")
64+
/// .header("content-type", "text/plain")
65+
/// .build();
66+
/// let response: Response = spin_sdk::http::send(request).await?;
67+
/// # Ok(())
68+
/// # }
69+
/// ```
70+
///
71+
/// Build and send an outgoing request without using the helper shortcut.
72+
///
73+
/// ```no_run
74+
/// use spin_sdk::http::{Method, Request, Response};
75+
///
76+
/// # #[tokio::main]
77+
/// # async fn main() -> anyhow::Result<()> {
78+
/// let mut request = Request::new(Method::Put, "https://example.com/message/safety");
79+
/// request.set_header("content-type", "text/plain");
80+
/// *request.body_mut() = "beware the crocodile".as_bytes().to_vec();
81+
/// let response: Response = spin_sdk::http::send(request).await?;
82+
/// # Ok(())
83+
/// # }
84+
/// ```
85+
///
86+
/// Build and send an outgoing request using the fluent builder.
87+
///
88+
/// ```no_run
89+
/// use spin_sdk::http::{Method, Request, Response};
90+
///
91+
/// # #[tokio::main]
92+
/// # async fn main() -> anyhow::Result<()> {
93+
/// let request = Request::builder()
94+
/// .uri("https://example.com/message/motivational")
95+
/// .method(Method::Put)
96+
/// .header("content-type", "text/plain")
97+
/// .body("the capybaras of creativity fly higher than the bluebirds of banality")
98+
/// .build();
99+
/// let response: Response = spin_sdk::http::send(request).await?;
100+
/// # Ok(())
101+
/// # }
102+
/// ```
23103
pub struct Request {
24104
/// The method of the request
25105
method: Method,
@@ -613,6 +693,59 @@ impl ResponseOutparam {
613693
}
614694

615695
/// Send an outgoing request
696+
///
697+
/// # Examples
698+
///
699+
/// Get the example.com home page:
700+
///
701+
/// ```no_run
702+
/// use spin_sdk::http::{Request, Response};
703+
///
704+
/// # #[tokio::main]
705+
/// # async fn main() -> anyhow::Result<()> {
706+
/// let request = Request::get("example.com").build();
707+
/// let response: Response = spin_sdk::http::send(request).await?;
708+
/// println!("{}", response.body().len());
709+
/// # Ok(())
710+
/// # }
711+
/// ```
712+
///
713+
/// Use the `http` crate Request type to send a data transfer value:
714+
///
715+
/// ```no_run
716+
/// use hyperium::Request;
717+
///
718+
/// #[derive(serde::Serialize)]
719+
/// struct User {
720+
/// name: String,
721+
/// }
722+
///
723+
/// impl spin_sdk::http::conversions::TryIntoBody for User {
724+
/// type Error = serde_json::Error;
725+
///
726+
/// fn try_into_body(self) -> Result<Vec<u8>, Self::Error> {
727+
/// serde_json::to_vec(&self)
728+
/// }
729+
/// }
730+
///
731+
/// # #[tokio::main]
732+
/// # async fn main() -> anyhow::Result<()> {
733+
/// let user = User {
734+
/// name: "Alice".to_owned(),
735+
/// };
736+
///
737+
/// let request = hyperium::Request::builder()
738+
/// .method("POST")
739+
/// .uri("https://example.com/users")
740+
/// .header("content-type", "application/json")
741+
/// .body(user)?;
742+
///
743+
/// let response: hyperium::Response<()> = spin_sdk::http::send(request).await?;
744+
///
745+
/// println!("{}", response.status().is_success());
746+
/// # Ok(())
747+
/// # }
748+
/// ```
616749
pub async fn send<I, O>(request: I) -> Result<O, SendError>
617750
where
618751
I: TryIntoOutgoingRequest,

src/key_value.rs

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,73 @@
33
//! This module provides a generic interface for key-value storage, which may be implemented by the host various
44
//! ways (e.g. via an in-memory table, a local file, or a remote database). Details such as consistency model and
55
//! durability will depend on the implementation and may vary from one to store to the next.
6+
//!
7+
//! # Examples
8+
//!
9+
//! Open the default store and set the 'message' key:
10+
//!
11+
//! ```no_run
12+
//! # fn main() -> anyhow::Result<()> {
13+
//! let store = spin_sdk::key_value::Store::open_default()?;
14+
//! store.set("message", "Hello world".as_bytes())?;
15+
//! # Ok(())
16+
//! # }
17+
//! ```
618
719
use super::wit::v2::key_value;
820

921
#[cfg(feature = "json")]
1022
use serde::{de::DeserializeOwned, Serialize};
1123

1224
#[doc(inline)]
13-
pub use key_value::{Error, Store};
25+
pub use key_value::Error;
26+
27+
/// An open key-value store.
28+
///
29+
/// # Examples
30+
///
31+
/// Open the default store and set the 'message' key:
32+
///
33+
/// ```no_run
34+
/// # fn main() -> anyhow::Result<()> {
35+
/// let store = spin_sdk::key_value::Store::open_default()?;
36+
/// store.set("message", "Hello world".as_bytes())?;
37+
/// # Ok(())
38+
/// # }
39+
/// ```
40+
///
41+
/// Open the default store and get the 'message' key:
42+
///
43+
/// ```no_run
44+
/// # fn main() -> anyhow::Result<()> {
45+
/// let store = spin_sdk::key_value::Store::open_default()?;
46+
/// let message = store.get("message")?;
47+
/// let response = message.unwrap_or_else(|| "not found".into());
48+
/// # Ok(())
49+
/// # }
50+
/// ```
51+
///
52+
/// Open a named store and list all the keys defined in it:
53+
///
54+
/// ```no_run
55+
/// # fn main() -> anyhow::Result<()> {
56+
/// let store = spin_sdk::key_value::Store::open("finance")?;
57+
/// let keys = store.get_keys()?;
58+
/// # Ok(())
59+
/// # }
60+
/// ```
61+
///
62+
/// Open the default store and delete the 'message' key:
63+
///
64+
/// ```no_run
65+
/// # fn main() -> anyhow::Result<()> {
66+
/// let store = spin_sdk::key_value::Store::open_default()?;
67+
/// store.delete("message")?;
68+
/// # Ok(())
69+
/// # }
70+
/// ```
71+
#[doc(inline)]
72+
pub use key_value::Store;
1473

1574
impl Store {
1675
/// Open the default store.
@@ -24,6 +83,31 @@ impl Store {
2483
impl Store {
2584
#[cfg(feature = "json")]
2685
/// Serialize the given data to JSON, then set it as the value for the specified `key`.
86+
///
87+
/// # Examples
88+
///
89+
/// Open the default store and save a customer information document against the customer ID:
90+
///
91+
/// ```no_run
92+
/// # use serde::{Deserialize, Serialize};
93+
/// #[derive(Deserialize, Serialize)]
94+
/// struct Customer {
95+
/// name: String,
96+
/// address: Vec<String>,
97+
/// }
98+
///
99+
/// # fn main() -> anyhow::Result<()> {
100+
/// let customer_id = "CR1234567";
101+
/// let customer = Customer {
102+
/// name: "Alice".to_owned(),
103+
/// address: vec!["Wonderland Way".to_owned()],
104+
/// };
105+
///
106+
/// let store = spin_sdk::key_value::Store::open_default()?;
107+
/// store.set_json(customer_id, &customer)?;
108+
/// # Ok(())
109+
/// # }
110+
/// ```
27111
pub fn set_json<T: Serialize>(
28112
&self,
29113
key: impl AsRef<str>,
@@ -34,6 +118,27 @@ impl Store {
34118

35119
#[cfg(feature = "json")]
36120
/// Deserialize an instance of type `T` from the value of `key`.
121+
///
122+
/// # Examples
123+
///
124+
/// Open the default store and retrieve a customer information document by customer ID:
125+
///
126+
/// ```no_run
127+
/// # use serde::{Deserialize, Serialize};
128+
/// #[derive(Deserialize, Serialize)]
129+
/// struct Customer {
130+
/// name: String,
131+
/// address: Vec<String>,
132+
/// }
133+
///
134+
/// # fn main() -> anyhow::Result<()> {
135+
/// let customer_id = "CR1234567";
136+
///
137+
/// let store = spin_sdk::key_value::Store::open_default()?;
138+
/// let customer = store.get_json::<Customer>(customer_id)?;
139+
/// # Ok(())
140+
/// # }
141+
/// ```
37142
pub fn get_json<T: DeserializeOwned>(
38143
&self,
39144
key: impl AsRef<str>,

src/lib.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub mod key_value;
1111
/// SQLite storage.
1212
pub mod sqlite;
1313

14-
/// Large Language Model APIs
14+
/// Large Language Model (Serverless AI) APIs
1515
pub mod llm;
1616

1717
/// Exports the procedural macros for writing handlers for Spin components.
@@ -57,13 +57,13 @@ extern "C" fn __spin_sdk_hash() {}
5757
/// Helpers for building Spin `wasi-http` components.
5858
pub mod http;
5959

60-
/// Implementation of the spin mqtt interface.
60+
/// MQTT messaging.
6161
#[allow(missing_docs)]
6262
pub mod mqtt {
6363
pub use super::wit::v2::mqtt::{Connection, Error, Payload, Qos};
6464
}
6565

66-
/// Implementation of the spin redis interface.
66+
/// Redis storage and messaging.
6767
#[allow(missing_docs)]
6868
pub mod redis {
6969
use std::hash::{Hash, Hasher};
@@ -99,16 +99,18 @@ pub mod redis {
9999
}
100100
}
101101

102-
/// Implementation of the spin postgres db interface.
102+
/// Spin 2 Postgres relational database storage. Applications that do not require
103+
/// Spin 2 support should use the `pg3` module instead.
103104
pub mod pg;
104105

105-
/// Implementation of the spin postgres v3 db interface.
106+
/// Postgres relational database storage.
106107
pub mod pg3;
107108

108-
/// Implementation of the Spin MySQL database interface.
109+
/// MySQL relational database storage.
109110
pub mod mysql;
110111

111112
#[doc(inline)]
113+
/// Component configuration variables.
112114
pub use wit::v2::variables;
113115

114116
#[doc(hidden)]

src/llm.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,49 @@
1-
pub use crate::wit::v2::llm::{
2-
self, EmbeddingsResult, EmbeddingsUsage, Error, InferencingParams, InferencingResult,
3-
InferencingUsage,
4-
};
1+
pub use crate::wit::v2::llm::{Error, InferencingParams, InferencingResult, InferencingUsage};
2+
3+
/// Provides access to the underlying WIT interface. You should not normally need
4+
/// to use this module: use the re-exports in this module instead.
5+
#[doc(inline)]
6+
pub use crate::wit::v2::llm;
7+
8+
/// The result of generating embeddings.
9+
///
10+
/// # Examples
11+
///
12+
/// Generate embeddings using the all-minilm-l6-v2 LLM.
13+
///
14+
/// ```no_run
15+
/// use spin_sdk::llm;
16+
///
17+
/// # fn main() -> anyhow::Result<()> {
18+
/// let text = &[
19+
/// "I've just broken a priceless turnip".to_owned(),
20+
/// ];
21+
///
22+
/// let embed_result = llm::generate_embeddings(llm::EmbeddingModel::AllMiniLmL6V2, text)?;
23+
///
24+
/// println!("prompt token count: {}", embed_result.usage.prompt_token_count);
25+
/// println!("embedding: {:?}", embed_result.embeddings.first());
26+
/// # Ok(())
27+
/// # }
28+
/// ```
29+
#[doc(inline)]
30+
pub use crate::wit::v2::llm::EmbeddingsResult;
31+
32+
/// Usage related to an embeddings generation request.
33+
///
34+
/// # Examples
35+
///
36+
/// ```no_run
37+
/// use spin_sdk::llm;
38+
///
39+
/// # fn main() -> anyhow::Result<()> {
40+
/// # let text = &[];
41+
/// let embed_result = llm::generate_embeddings(llm::EmbeddingModel::AllMiniLmL6V2, text)?;
42+
/// println!("prompt token count: {}", embed_result.usage.prompt_token_count);
43+
/// # Ok(())
44+
/// # }
45+
/// ```
46+
pub use crate::wit::v2::llm::EmbeddingsUsage;
547

648
/// The model use for inferencing
749
#[allow(missing_docs)]

0 commit comments

Comments
 (0)