lib.rs 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. use proc_macro::TokenStream;
  2. use quote::ToTokens;
  3. use server_fn_macro::*;
  4. /// Declares that a function is a [server function](dioxus_fullstack). This means that
  5. /// its body will only run on the server, i.e., when the `ssr` feature is enabled.
  6. ///
  7. /// If you call a server function from the client (i.e., when the `csr` or `hydrate` features
  8. /// are enabled), it will instead make a network request to the server.
  9. ///
  10. /// You can specify one, two, or three arguments to the server function:
  11. /// 1. **Required**: A type name that will be used to identify and register the server function
  12. /// (e.g., `MyServerFn`).
  13. /// 2. *Optional*: A URL prefix at which the function will be mounted when it’s registered
  14. /// (e.g., `"/api"`). Defaults to `"/"`.
  15. /// 3. *Optional*: either `"Cbor"` (specifying that it should use the binary `cbor` format for
  16. /// serialization), `"Url"` (specifying that it should be use a URL-encoded form-data string).
  17. /// Defaults to `"Url"`. If you want to use this server function
  18. /// using Get instead of Post methods, the encoding must be `"GetCbor"` or `"GetJson"`.
  19. ///
  20. /// The server function itself can take any number of arguments, each of which should be serializable
  21. /// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](https::/docs.rs/dioxus-fullstack/latest/dixous_server/prelude/struct.DioxusServerContext.html),
  22. /// which will be injected *on the server side.* This can be used to inject the raw HTTP request or other
  23. /// server-side context into the server function.
  24. ///
  25. /// ```ignore
  26. /// # use dioxus_fullstack::prelude::*; use serde::{Serialize, Deserialize};
  27. /// # #[derive(Serialize, Deserialize)]
  28. /// # pub struct Post { }
  29. /// #[server(ReadPosts, "/api")]
  30. /// pub async fn read_posts(how_many: u8, query: String) -> Result<Vec<Post>, ServerFnError> {
  31. /// // do some work on the server to access the database
  32. /// todo!()
  33. /// }
  34. /// ```
  35. ///
  36. /// Note the following:
  37. /// - You must **register** the server function by calling `T::register()` somewhere in your main function.
  38. /// - **Server functions must be `async`.** Even if the work being done inside the function body
  39. /// can run synchronously on the server, from the client’s perspective it involves an asynchronous
  40. /// function call.
  41. /// - **Server functions must return `Result<T, ServerFnError>`.** Even if the work being done
  42. /// inside the function body can’t fail, the processes of serialization/deserialization and the
  43. /// network call are fallible.
  44. /// - **Return types must implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html).**
  45. /// This should be fairly obvious: we have to serialize arguments to send them to the server, and we
  46. /// need to deserialize the result to return it to the client.
  47. /// - **Arguments must be implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html)
  48. /// and [`DeserializeOwned`](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html).**
  49. /// They are serialized as an `application/x-www-form-urlencoded`
  50. /// form data using [`serde_urlencoded`](https://docs.rs/serde_urlencoded/latest/serde_urlencoded/) or as `application/cbor`
  51. /// using [`cbor`](https://docs.rs/cbor/latest/cbor/).
  52. /// - **The [DioxusServerContext](https::/docs.rs/dioxus-fullstack/latest/dixous_server/prelude/struct.DioxusServerContext.html) comes from the server.** Optionally, the first argument of a server function
  53. /// can be a [DioxusServerContext](https::/docs.rs/dioxus-fullstack/latest/dixous_server/prelude/struct.DioxusServerContext.html). This scope can be used to inject dependencies like the HTTP request
  54. /// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client.
  55. #[proc_macro_attribute]
  56. pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
  57. let context = ServerContext {
  58. ty: syn::parse_quote!(DioxusServerContext),
  59. path: syn::parse_quote!(::dioxus_fullstack::prelude::DioxusServerContext),
  60. };
  61. match server_macro_impl(
  62. args.into(),
  63. s.into(),
  64. Some(context),
  65. Some(syn::parse_quote!(::dioxus_fullstack::prelude::server_fn)),
  66. ) {
  67. Err(e) => e.to_compile_error().into(),
  68. Ok(s) => s.to_token_stream().into(),
  69. }
  70. }