Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions .llms-snapshots/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3077,6 +3077,170 @@ The following functions from `@junobuild/core` are used in this example:
| `uploadFile` | Upload a file to storage | [`src/components/Modal.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Modal.vue) | [Upload file](/docs/build/storage/development.md#upload-file) |
| `deleteAsset` | Delete a file from storage | [`src/components/Delete.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Delete.vue) | [Delete asset](/docs/build/storage/development.md#delete-asset) |

# Rust Assertions Example

This example demonstrates how to write a **custom assertion** in **Rust** for a Juno **serverless function**. It shows how to intercept and validate data operations—such as rejecting specific content—before it's written to the datastore.

The project includes a minimal frontend to help trigger and test the logic, but the primary focus is the backend assertion.

You can browse the source code here: [github.com/junobuild/examples/tree/main/rust/assertions](https://github.com/junobuild/examples/tree/main/rust/assertions)

---

## Folder Structure

```
rust/assertions/├── src/│ ├── satellite/ # Rust Satellite serverless function│ │ ├── src/│ │ │ └── lib.rs # Main Rust logic for Satellite│ │ ├── satellite.did # Candid interface definition│ │ └── Cargo.toml # Rust package config├── src/components/ # Minimal frontend React components├── juno.config.ts # Juno Satellite configuration├── package.json # Frontend dependencies└── ...
```

---

## Key Features

* **Custom Assertions in Rust**: Demonstrates how to reject or validate data before it's saved, using Rust serverless functions.
* **Serverless Integration**: Runs as a Satellite function and integrates with Juno's datastore and authentication system.
* **Minimal UI for Testing**: A simple frontend is included to test and demonstrate the assertion logic in action.

---

## Main Backend Components

* **src/satellite/src/lib.rs**: The core Rust logic for the Satellite serverless function. Implements the custom assertions (e.g., only allow certain valid inputs, etc.).
* **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function.

---

## Example: Custom Assertion in Rust

Here’s the actual Rust logic from `lib.rs`:

```
// This example defines a custom assertion in a Juno Satellite using Rust.// It checks if a document being saved to the "notes" collection contains the word "hello".// If it does, the assertion rejects the operation and logs a message.use ic_cdk::print;use junobuild_macros::assert_set_doc;use junobuild_satellite::{include_satellite, AssertSetDocContext};use junobuild_utils::decode_doc_data;use serde::{Deserialize, Serialize};#[derive(Serialize, Deserialize)]struct Note { text: String, url: Option<String>,}#[assert_set_doc(collections = ["notes"])]fn assert_set_doc(context: AssertSetDocContext) -> Result<(), String> { let note = decode_doc_data::<Note>(&context.data.data.proposed.data)?; if note.text.to_lowercase().contains("hello") { print(format!("❌ Rejected note containing 'hello': {}", note.text)); return Err("The note should not contain the keyword 'hello'.".to_string()); } print(format!("✅ Note accepted: {}", note.text)); Ok(())}include_satellite!();
```

**Explanation:**

* Defines a `Note` struct with `text` and optional `url` fields. Similar as the fields used in the frontend.
* Uses the `#[assert_set_doc]` macro to create a custom assertion for the `notes` collection.
* When a note is created or updated, the assertion checks if the note's text contains the word "hello" (case-insensitive).
* If it does, the note is rejected and an error message is returned; otherwise, the note is accepted.
* Prints a message to the log for both accepted and rejected notes.
* `include_satellite!();` brings in the necessary boilerplate for the Juno Satellite runtime.

---

## How to Run

1. **Clone the repo**:

```
git clone https://github.com/junobuild/examplescd rust/assertions
```

2. **Install dependencies**:

```
npm install
```

3. **Start Juno local emulator**:

**Important:**

Requires the Juno CLI to be available `npm i -g @junobuild/cli`

```
juno dev start
```

4. **Create a Satellite** for local dev:

* Visit [http://localhost:5866](http://localhost:5866) and follow the instructions.
* Update `juno.config.ts` with your Satellite ID.

5. **Create required collections**:

* `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore)
* `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage)

6. **Start the frontend dev server** (in a separate terminal):

```
npm run dev
```

6. **Build the serverless functions** (in a separate terminal):

```
juno functions build
```

The emulator will automatically upgrade your Satellite and live reload the changes.

---

## Juno-Specific Configuration

* **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details.
* **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information.

---

## Production Deployment

* Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet.
* Update `juno.config.ts` with the production Satellite ID.
* Build and deploy the frontend:

```
npm run buildjuno deploy
```

* Build and upgrade the serverless functions:

```
juno functions buildjuno functions upgrade
```

---

## Notes

* This example focuses on the Rust serverless function; the frontend is intentionally minimal and only included for demonstration purposes.
* Use this project as a starting point for writing custom assertions and backend logic in Rust with Juno.

---

## Real-World Example

Want to see how assertions and serverless logic are used in a live project?

Check out [proposals.network](https://proposals.network), an open-source app built with Juno:

* GitHub: [github.com/peterpeterparker/proposals.network](https://github.com/peterpeterparker/proposals.network)
* Example logic: [src/satellite/src/lib.rs](https://github.com/peterpeterparker/proposals.network/blob/main/src/satellite/src/lib.rs)

This app uses:

* `#[on_delete_doc]` and `#[assert_delete_doc]` to validate and clean up related documents and assets
* Shared helper modules like `assert`, `delete`, and `types` to keep logic organized
* A real-world pattern of chaining asset/document deletions with assertions

It’s a great reference for more advanced setups and multi-collection coordination.

---

## References

* [Serverless Functions Guide](/docs/guides/rust.md)
* [Rust Functions Development](/docs/build/functions.md)
* [Rust SDK Reference](/docs/reference/functions/rust/sdk.md)
* [Rust Utils Reference](/docs/reference/functions/rust/utils.md)
* [Run Local Development](/docs/guides/local-development.md)
* [CLI Reference](/docs/reference/cli.md)
* [Configuration Reference](/docs/reference/configuration.md)
* [Datastore Collections](/docs/build/datastore/collections.md)

# Using Juno with AI

If you're using AI to build with Juno, you can use our `llms.txt` files to help AI tools better understand the platform.
Expand Down
4 changes: 4 additions & 0 deletions .llms-snapshots/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ Juno is your self-contained serverless platform for building full-stack web apps
- [Vanilla JavaScript Example](https://juno.build/docs/examples/frontend/vanilla-javascript.md): A fullstack note-taking app built with vanilla JavaScript, and Tailwind CSS using Juno for authentication, data, and file storage.
- [Vue Example](https://juno.build/docs/examples/frontend/vue.md): A fullstack note-taking app built with Vue, and Tailwind CSS using Juno for authentication, data, and file storage.

## Examples - Functions - Rust

- [Rust Assertions Example](https://juno.build/docs/examples/functions/rust/assertions.md): An example demonstrating how to write custom assertions in Rust for Juno serverless functions.

## Guides

- [AI](https://juno.build/docs/guides/ai.md): Learn how to use Juno's llms.txt files to provide AI tools with better context for building serverless functions, deploying satellites, and integrating the SDK.
Expand Down
215 changes: 215 additions & 0 deletions docs/examples/functions/rust/assertions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
---
title: Rust Assertions Example
description: An example demonstrating how to write custom assertions in Rust for Juno serverless functions.
keywords: [rust, assertion, serverless, juno, satellite, example]
sidebar_label: Assertions
---

# Rust Assertions Example

This example demonstrates how to write a **custom assertion** in **Rust** for a Juno **serverless function**. It shows how to intercept and validate data operations—such as rejecting specific content—before it's written to the datastore.

The project includes a minimal frontend to help trigger and test the logic, but the primary focus is the backend assertion.

You can browse the source code here: [github.com/junobuild/examples/tree/main/rust/assertions](https://github.com/junobuild/examples/tree/main/rust/assertions)

---

## Folder Structure

```
rust/assertions/
├── src/
│ ├── satellite/ # Rust Satellite serverless function
│ │ ├── src/
│ │ │ └── lib.rs # Main Rust logic for Satellite
│ │ ├── satellite.did # Candid interface definition
│ │ └── Cargo.toml # Rust package config
├── src/components/ # Minimal frontend React components
├── juno.config.ts # Juno Satellite configuration
├── package.json # Frontend dependencies
└── ...
```

---

## Key Features

- **Custom Assertions in Rust**: Demonstrates how to reject or validate data before it's saved, using Rust serverless functions.
- **Serverless Integration**: Runs as a Satellite function and integrates with Juno's datastore and authentication system.
- **Minimal UI for Testing**: A simple frontend is included to test and demonstrate the assertion logic in action.

---

## Main Backend Components

- **src/satellite/src/lib.rs**: The core Rust logic for the Satellite serverless function. Implements the custom assertions (e.g., only allow certain valid inputs, etc.).
- **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function.

---

## Example: Custom Assertion in Rust

Here’s the actual Rust logic from `lib.rs`:

```rust
// This example defines a custom assertion in a Juno Satellite using Rust.
// It checks if a document being saved to the "notes" collection contains the word "hello".
// If it does, the assertion rejects the operation and logs a message.

use ic_cdk::print;
use junobuild_macros::assert_set_doc;
use junobuild_satellite::{include_satellite, AssertSetDocContext};
use junobuild_utils::decode_doc_data;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct Note {
text: String,
url: Option<String>,
}

#[assert_set_doc(collections = ["notes"])]
fn assert_set_doc(context: AssertSetDocContext) -> Result<(), String> {
let note = decode_doc_data::<Note>(&context.data.data.proposed.data)?;

if note.text.to_lowercase().contains("hello") {
print(format!("❌ Rejected note containing 'hello': {}", note.text));
return Err("The note should not contain the keyword 'hello'.".to_string());
}

print(format!("✅ Note accepted: {}", note.text));

Ok(())
}

include_satellite!();
```

**Explanation:**

- Defines a `Note` struct with `text` and optional `url` fields. Similar as the fields used in the frontend.
- Uses the `#[assert_set_doc]` macro to create a custom assertion for the `notes` collection.
- When a note is created or updated, the assertion checks if the note's text contains the word "hello" (case-insensitive).
- If it does, the note is rejected and an error message is returned; otherwise, the note is accepted.
- Prints a message to the log for both accepted and rejected notes.
- `include_satellite!();` brings in the necessary boilerplate for the Juno Satellite runtime.

---

## How to Run

1. **Clone the repo**:

```bash
git clone https://github.com/junobuild/examples
cd rust/assertions
```

2. **Install dependencies**:

```bash
npm install
```

3. **Start Juno local emulator**:

:::important

Requires the Juno CLI to be available `npm i -g @junobuild/cli`

:::

```bash
juno dev start
```

4. **Create a Satellite** for local dev:

- Visit [http://localhost:5866](http://localhost:5866) and follow the instructions.
- Update `juno.config.ts` with your Satellite ID.

5. **Create required collections**:

- `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore)
- `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage)

6. **Start the frontend dev server** (in a separate terminal):

```bash
npm run dev
```

6. **Build the serverless functions** (in a separate terminal):

```bash
juno functions build
```

The emulator will automatically upgrade your Satellite and live reload the changes.

---

## Juno-Specific Configuration

- **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](../../../reference/configuration.mdx) for details.
- **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](../../../reference/plugins.mdx#vite-plugin) for more information.

---

## Production Deployment

- Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet.
- Update `juno.config.ts` with the production Satellite ID.
- Build and deploy the frontend:

```bash
npm run build
juno deploy
```

- Build and upgrade the serverless functions:

```bash
juno functions build
juno functions upgrade
```

---

## Notes

- This example focuses on the Rust serverless function; the frontend is intentionally minimal and only included for demonstration purposes.
- Use this project as a starting point for writing custom assertions and backend logic in Rust with Juno.

---

## Real-World Example

Want to see how assertions and serverless logic are used in a live project?

Check out [proposals.network](https://proposals.network), an open-source app built with Juno:

- GitHub: [github.com/peterpeterparker/proposals.network](https://github.com/peterpeterparker/proposals.network)
- Example logic: [src/satellite/src/lib.rs](https://github.com/peterpeterparker/proposals.network/blob/main/src/satellite/src/lib.rs)

This app uses:

- `#[on_delete_doc]` and `#[assert_delete_doc]` to validate and clean up related documents and assets
- Shared helper modules like `assert`, `delete`, and `types` to keep logic organized
- A real-world pattern of chaining asset/document deletions with assertions

It’s a great reference for more advanced setups and multi-collection coordination.

---

## References

- [Serverless Functions Guide](../../../guides/rust.mdx)
- [Rust Functions Development](../../../build/functions/index.md)
- [Rust SDK Reference](../../../reference/functions/rust/sdk.mdx)
- [Rust Utils Reference](../../../reference/functions/rust/utils.mdx)
- [Run Local Development](../../../guides/local-development.mdx)
- [CLI Reference](../../../reference/cli)
- [Configuration Reference](../../../reference/configuration.mdx)
- [Datastore Collections](../../../build/datastore/collections.md)
Loading