#[server]Expand description
Declares that a function is a server function.
This means that its body will only run on the server, i.e., when the ssr
feature is enabled on this crate.
§Usage
#[server]
pub async fn blog_posts(
category: String,
) -> ServerFnResult<Vec<BlogPost>> {
let posts = load_posts(&category).await?;
// maybe do some other work
Ok(posts)
}§Named Arguments
You can use any combination of the following named arguments:
name: sets the identifier for the server function’s type, which is a struct created to hold the arguments (defaults to the function identifier in PascalCase). Example:name = MyServerFunction.prefix: a prefix at which the server function handler will be mounted (defaults to/api). Example:prefix = "/my_api".endpoint: specifies the exact path at which the server function handler will be mounted, relative to the prefix (defaults to the function name followed by unique hash). Example:endpoint = "my_fn".input: the encoding for the arguments (defaults toPostUrl).- The
inputargument specifies how the function arguments are encoded for transmission. - Acceptable values include:
PostUrl: APOSTrequest with URL-encoded arguments, suitable for form-like submissions.Json: APOSTrequest where the arguments are encoded as JSON. This is a common choice for modern APIs.Cbor: APOSTrequest with CBOR-encoded arguments, useful for binary data transmission with compact encoding.GetUrl: AGETrequest with URL-encoded arguments, suitable for simple queries or when data fits in the URL.GetCbor: AGETrequest with CBOR-encoded arguments, useful for query-style APIs when the payload is binary.
- The
output: the encoding for the response (defaults toJson).- The
outputargument specifies how the server should encode the response data. - Acceptable values include:
Json: A response encoded as JSON (default). This is ideal for most web applications.Cbor: A response encoded in the CBOR format for efficient, binary-encoded data.
- The
client: a customClientimplementation that will be used for this server function. This allows customization of the client-side behavior if needed.encoding: (legacy, may be deprecated in future) specifies the encoding, which may be one of the following (not case sensitive):"Url":POSTrequest with URL-encoded arguments and JSON response"GetUrl":GETrequest with URL-encoded arguments and JSON response"Cbor":POSTrequest with CBOR-encoded arguments and response"GetCbor":GETrequest with URL-encoded arguments and CBOR response
reqandres: specify the HTTP request and response types to be used on the server. These are typically necessary if you are integrating with a custom server framework (other than Actix/Axum). Example:req = SomeRequestType,res = SomeResponseType.
§Advanced Usage of input and output Fields
The input and output fields allow you to customize how arguments and responses are encoded and decoded.
These fields impose specific trait bounds on the types you use. Here are detailed examples for different scenarios:
§output = StreamingJson
Setting the output type to StreamingJson requires the return type to implement From<JsonStream<T>>,
where T implements serde::Serialize and serde::de::DeserializeOwned.
#[server(output = StreamingJson)]
pub async fn json_stream_fn() -> Result<JsonStream<String>, ServerFnError> {
todo!()
}§output = StreamingText
Setting the output type to StreamingText requires the return type to implement From<TextStream>.
#[server(output = StreamingText)]
pub async fn text_stream_fn() -> Result<TextStream, ServerFnError> {
todo!()
}§output = PostUrl
Setting the output type to PostUrl requires the return type to implement Serialize and Deserialize.
Note that this uses serde_qs, which imposes the following constraints:
- The structure must be less than 5 levels deep.
- The structure must not contain any
serde(flatten)attributes.
#[server(output = PostUrl)]
pub async fn form_fn() -> Result<TextStream, ServerFnError> {
todo!()
}These examples illustrate how the output type impacts the bounds and expectations for your server function. Ensure your return types comply with these requirements.
#[server(
name = SomeStructName,
prefix = "/my_api",
endpoint = "my_fn",
input = Cbor,
output = Json
)]
pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<usize> {
unimplemented!()
}
// expands to
#[derive(Deserialize, Serialize)]
struct SomeStructName {
input: Vec<String>
}
impl ServerFn for SomeStructName {
const PATH: &'static str = "/my_api/my_fn";
// etc.
}§Adding layers to server functions
Layers allow you to transform the request and response of a server function. You can use layers to add authentication, logging, or other functionality to your server functions. Server functions integrate with the tower ecosystem, so you can use any layer that is compatible with tower.
Common layers include:
tower_http::trace::TraceLayerfor tracing requests and responsestower_http::compression::CompressionLayerfor compressing large responsestower_http::cors::CorsLayerfor adding CORS headers to responsestower_http::timeout::TimeoutLayerfor adding timeouts to requeststower_sessions::service::SessionManagerLayerfor adding session management to requests
You can add a tower Layer to your server function with the middleware attribute:
#[server]
// The TraceLayer will log all requests to the console
#[middleware(tower_http::timeout::TimeoutLayer::new(std::time::Duration::from_secs(5)))]
pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<usize> {
unimplemented!()
}§Extracting additional data from requests
Server functions automatically handle serialization and deserialization of arguments and responses.
However, you may want to extract additional data from the request, such as the user’s session or
authentication information. You can do this with the extract function. This function returns any
type that implements the FromRequestParts
trait:
#[server]
pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<String> {
let headers: axum::http::header::HeaderMap = extract().await?;
Ok(format!("The server got a request with headers: {:?}", headers))
}§Sharing data with server functions
You may need to share context with your server functions like a database pool. Server
functions can access any context provided through the launch builder. You can access
this context with the FromContext extractor:
#[derive(Clone, Copy, Debug)]
struct DatabasePool;
fn main() {
LaunchBuilder::new()
.with_context(server_only! {
DatabasePool
})
.launch(app);
}
#[server]
pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<String> {
let FromContext(pool): FromContext<DatabasePool> = extract().await?;
Ok(format!("The server read {:?} from the shared context", pool))
}