mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 14:52:35 -05:00
Compare commits
7 Commits
fix-error-
...
server-fn-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7b08cf9cc | ||
|
|
7e16d115e3 | ||
|
|
b043f829a6 | ||
|
|
af3596a608 | ||
|
|
3c66712f4d | ||
|
|
ec60a0f4fe | ||
|
|
f415f7b146 |
@@ -97,6 +97,14 @@ In other words, you have two choices:
|
||||
|
||||
**But remember**: Leptos will handle all the details of this encoding and decoding for you. When you use a server function, it looks just like calling any other asynchronous function!
|
||||
|
||||
> **Why not `PUT` or `DELETE`? Why URL/form encoding, and not JSON?**
|
||||
>
|
||||
> These are reasonable questions. Much of the web is built on REST API patterns that encourage the use of semantic HTTP methods like `DELETE` to delete an item from a database, and many devs are accustomed to sending data to APIs in the JSON format.
|
||||
>
|
||||
> The reason we use `POST` or `GET` with URL-encoded data by default is the `<form>` support. For better or for worse, HTML forms don’t support `PUT` or `DELETE`, and they don’t support sending JSON. This means that if you use anything but a `GET` or `POST` request with URL-encoded data, it can only work once WASM has loaded. As we’ll see [in a later chapter](../progressive_enhancement), this isn’t always a great idea.
|
||||
>
|
||||
> The CBOR encoding is suported for historical reasons; an earlier version of server functions used a URL encoding that didn’t support nested objects like structs or vectors as server function arguments, which CBOR did. But note that the CBOR forms encounter the same issue as `PUT`, `DELETE`, or JSON: they do not degrade gracefully if the WASM version of your app is not available.
|
||||
|
||||
## An Important Note on Security
|
||||
|
||||
Server functions are a cool technology, but it’s very important to remember. **Server functions are not magic; they’re syntax sugar for defining a public API.** The _body_ of a server function is never made public; it’s just part of your server binary. But the server function is a publicly accessible API endpoint, and it’s return value is just a JSON or similar blob. You should _never_ return something sensitive from a server function.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::Children;
|
||||
use leptos_dom::{Errors, HydrationCtx, IntoView};
|
||||
use leptos_dom::{Errors, IntoView};
|
||||
use leptos_macro::{component, view};
|
||||
use leptos_reactive::{
|
||||
create_rw_signal, provide_context, signal_prelude::*, RwSignal, Scope,
|
||||
@@ -28,7 +28,7 @@ use leptos_reactive::{
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
#[component]
|
||||
#[component(transparent)]
|
||||
pub fn ErrorBoundary<F, IV>(
|
||||
cx: Scope,
|
||||
/// The components inside the tag which will get rendered
|
||||
@@ -40,7 +40,6 @@ where
|
||||
F: Fn(Scope, RwSignal<Errors>) -> IV + 'static,
|
||||
IV: IntoView,
|
||||
{
|
||||
_ = HydrationCtx::next_component();
|
||||
let errors: RwSignal<Errors> = create_rw_signal(cx, Errors::default());
|
||||
|
||||
provide_context(cx, errors);
|
||||
|
||||
@@ -828,7 +828,7 @@ fn apply_diff<T, EF, V>(
|
||||
}
|
||||
|
||||
for DiffOpRemove { at } in &diff.removed {
|
||||
let item_to_remove = std::mem::take(&mut children[*at]).unwrap();
|
||||
let item_to_remove = children[*at].take().unwrap();
|
||||
|
||||
item_to_remove.prepare_for_move();
|
||||
}
|
||||
@@ -910,21 +910,34 @@ fn apply_diff<T, EF, V>(
|
||||
|
||||
/// Unpacks adds and moves into a sequence of interleaved
|
||||
/// add and move commands. Move commands will always return
|
||||
/// with a `len == 1` and `is_dense = true`.
|
||||
/// with a `len == 1`.
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
fn unpack_moves(diff: &Diff) -> (Vec<DiffOpMove>, Vec<DiffOpAdd>) {
|
||||
let mut moves = Vec::with_capacity(diff.items_to_move);
|
||||
let mut adds = Vec::with_capacity(diff.added.len());
|
||||
|
||||
let mut removes_iter = diff.removed.iter();
|
||||
let mut adds_iter = diff.added.iter();
|
||||
let mut moves_iter = diff.moved.iter();
|
||||
|
||||
let mut removes_next = removes_iter.next();
|
||||
let mut adds_next = adds_iter.next();
|
||||
let mut moves_next = moves_iter.next().copied();
|
||||
|
||||
for i in 0..diff.items_to_move + diff.added.len() {
|
||||
let mut from_offset: usize = 0;
|
||||
|
||||
for i in 0..diff.items_to_move + diff.added.len() + diff.removed.len() {
|
||||
match (adds_next, &mut moves_next) {
|
||||
(Some(add), Some(move_)) => {
|
||||
if let Some(DiffOpRemove { at }) = removes_next {
|
||||
if *at == i {
|
||||
from_offset += 1;
|
||||
removes_next = removes_iter.next();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if add.at == i {
|
||||
adds.push(*add);
|
||||
|
||||
@@ -932,6 +945,7 @@ fn unpack_moves(diff: &Diff) -> (Vec<DiffOpMove>, Vec<DiffOpAdd>) {
|
||||
} else {
|
||||
let mut single_move = *move_;
|
||||
single_move.len = 1;
|
||||
single_move.from -= from_offset;
|
||||
|
||||
moves.push(single_move);
|
||||
|
||||
@@ -950,8 +964,18 @@ fn unpack_moves(diff: &Diff) -> (Vec<DiffOpMove>, Vec<DiffOpAdd>) {
|
||||
adds_next = adds_iter.next();
|
||||
}
|
||||
(None, Some(move_)) => {
|
||||
if let Some(DiffOpRemove { at }) = removes_next {
|
||||
if *at == i {
|
||||
from_offset += 1;
|
||||
removes_next = removes_iter.next();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let mut single_move = *move_;
|
||||
single_move.len = 1;
|
||||
single_move.from -= from_offset;
|
||||
|
||||
moves.push(single_move);
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ where
|
||||
E: Error + Send + Sync + 'static,
|
||||
{
|
||||
fn into_view(self, cx: leptos_reactive::Scope) -> crate::View {
|
||||
let id = ErrorKey(HydrationCtx::peek().fragment.to_string().into());
|
||||
let id = ErrorKey(HydrationCtx::peek().id.to_string().into());
|
||||
let errors = use_context::<RwSignal<Errors>>(cx);
|
||||
match self {
|
||||
Ok(stuff) => {
|
||||
|
||||
@@ -840,6 +840,50 @@ pub fn slot(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
/// - **The `Scope` comes from the server.** Optionally, the first argument of a server function
|
||||
/// can be a Leptos `Scope`. This scope can be used to inject dependencies like the HTTP request
|
||||
/// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client.
|
||||
///
|
||||
/// ## Server Function Encodings
|
||||
///
|
||||
/// By default, the server function call is a `POST` request that serializes the arguments as URL-encoded form data in the body
|
||||
/// of the request. But there are a few other methods supported. Optionally, we can provide another argument to the `#[server]`
|
||||
/// macro to specify an alternate encoding:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[server(AddTodo, "/api", "Url")]
|
||||
/// #[server(AddTodo, "/api", "GetJson")]
|
||||
/// #[server(AddTodo, "/api", "Cbor")]
|
||||
/// #[server(AddTodo, "/api", "GetCbor")]
|
||||
/// ```
|
||||
///
|
||||
/// The four options use different combinations of HTTP verbs and encoding methods:
|
||||
///
|
||||
/// | Name | Method | Request | Response |
|
||||
/// | ----------------- | ------ | ----------- | -------- |
|
||||
/// | **Url** (default) | POST | URL encoded | JSON |
|
||||
/// | **GetJson** | GET | URL encoded | JSON |
|
||||
/// | **Cbor** | POST | CBOR | CBOR |
|
||||
/// | **GetCbor** | GET | URL encoded | CBOR |
|
||||
///
|
||||
/// In other words, you have two choices:
|
||||
///
|
||||
/// - `GET` or `POST`? This has implications for things like browser or CDN caching; while `POST` requests should not be cached,
|
||||
/// `GET` requests can be.
|
||||
/// - Plain text (arguments sent with URL/form encoding, results sent as JSON) or a binary format (CBOR, encoded as a base64
|
||||
/// string)?
|
||||
///
|
||||
/// ## Why not `PUT` or `DELETE`? Why URL/form encoding, and not JSON?**
|
||||
///
|
||||
/// These are reasonable questions. Much of the web is built on REST API patterns that encourage the use of semantic HTTP
|
||||
/// methods like `DELETE` to delete an item from a database, and many devs are accustomed to sending data to APIs in the
|
||||
/// JSON format.
|
||||
///
|
||||
/// The reason we use `POST` or `GET` with URL-encoded data by default is the `<form>` support. For better or for worse,
|
||||
/// HTML forms don’t support `PUT` or `DELETE`, and they don’t support sending JSON. This means that if you use anything
|
||||
/// but a `GET` or `POST` request with URL-encoded data, it can only work once WASM has loaded.
|
||||
///
|
||||
/// The CBOR encoding is suported for historical reasons; an earlier version of server functions used a URL encoding that
|
||||
/// didn’t support nested objects like structs or vectors as server function arguments, which CBOR did. But note that the
|
||||
/// CBOR forms encounter the same issue as `PUT`, `DELETE`, or JSON: they do not degrade gracefully if the WASM version of
|
||||
/// your app is not available.
|
||||
#[proc_macro_attribute]
|
||||
#[proc_macro_error]
|
||||
pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
|
||||
@@ -70,6 +70,50 @@
|
||||
//! - **The [Scope](leptos_reactive::Scope) comes from the server.** Optionally, the first argument of a server function
|
||||
//! can be a Leptos [Scope](leptos_reactive::Scope). This scope can be used to inject dependencies like the HTTP request
|
||||
//! or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client.
|
||||
//!
|
||||
//! ## Server Function Encodings
|
||||
//!
|
||||
//! By default, the server function call is a `POST` request that serializes the arguments as URL-encoded form data in the body
|
||||
//! of the request. But there are a few other methods supported. Optionally, we can provide another argument to the `#[server]`
|
||||
//! macro to specify an alternate encoding:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! #[server(AddTodo, "/api", "Url")]
|
||||
//! #[server(AddTodo, "/api", "GetJson")]
|
||||
//! #[server(AddTodo, "/api", "Cbor")]
|
||||
//! #[server(AddTodo, "/api", "GetCbor")]
|
||||
//! ```
|
||||
//!
|
||||
//! The four options use different combinations of HTTP verbs and encoding methods:
|
||||
//!
|
||||
//! | Name | Method | Request | Response |
|
||||
//! | ----------------- | ------ | ----------- | -------- |
|
||||
//! | **Url** (default) | POST | URL encoded | JSON |
|
||||
//! | **GetJson** | GET | URL encoded | JSON |
|
||||
//! | **Cbor** | POST | CBOR | CBOR |
|
||||
//! | **GetCbor** | GET | URL encoded | CBOR |
|
||||
//!
|
||||
//! In other words, you have two choices:
|
||||
//!
|
||||
//! - `GET` or `POST`? This has implications for things like browser or CDN caching; while `POST` requests should not be cached,
|
||||
//! `GET` requests can be.
|
||||
//! - Plain text (arguments sent with URL/form encoding, results sent as JSON) or a binary format (CBOR, encoded as a base64
|
||||
//! string)?
|
||||
//!
|
||||
//! ## Why not `PUT` or `DELETE`? Why URL/form encoding, and not JSON?**
|
||||
//!
|
||||
//! These are reasonable questions. Much of the web is built on REST API patterns that encourage the use of semantic HTTP
|
||||
//! methods like `DELETE` to delete an item from a database, and many devs are accustomed to sending data to APIs in the
|
||||
//! JSON format.
|
||||
//!
|
||||
//! The reason we use `POST` or `GET` with URL-encoded data by default is the `<form>` support. For better or for worse,
|
||||
//! HTML forms don’t support `PUT` or `DELETE`, and they don’t support sending JSON. This means that if you use anything
|
||||
//! but a `GET` or `POST` request with URL-encoded data, it can only work once WASM has loaded.
|
||||
//!
|
||||
//! The CBOR encoding is suported for historical reasons; an earlier version of server functions used a URL encoding that
|
||||
//! didn’t support nested objects like structs or vectors as server function arguments, which CBOR did. But note that the
|
||||
//! CBOR forms encounter the same issue as `PUT`, `DELETE`, or JSON: they do not degrade gracefully if the WASM version of
|
||||
//! your app is not available.
|
||||
|
||||
use leptos_reactive::*;
|
||||
pub use server_fn::{Encoding, Payload, ServerFnError};
|
||||
|
||||
Reference in New Issue
Block a user