Skip to content

Commit 4c70243

Browse files
docs: callable functions (also called custom functions) (#667)
* docs: callable functions Signed-off-by: David Dal Busco <david.dalbusco@outlook.com> * feat: link Signed-off-by: David Dal Busco <david.dalbusco@outlook.com> * 📄 Update LLMs.txt snapshot for PR review --------- Signed-off-by: David Dal Busco <david.dalbusco@outlook.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 934eca8 commit 4c70243

6 files changed

Lines changed: 236 additions & 80 deletions

File tree

.llms-snapshots/llms-full.txt

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,33 +2272,26 @@ import { getDoc } from "@junobuild/core";await getDoc({ collection: "my_collect
22722272

22732273
Functions are a set of features enabling developers to extend the native capabilities of [Satellites](/docs/terminology.md#satellite) using Rust or TypeScript. They let you define serverless behaviors directly within your containerized environment.
22742274

2275-
Triggered by events like document and asset operations, they allow you to automatically run backend code or assertions. These functions are shipped with your container and don’t require you to manage or scale your own servers.
2275+
There are two types of functions:
22762276

2277-
---
2278-
2279-
## How does it work?
2280-
2281-
Functions are defined using hooks that automatically respond to document and asset events such as create, update, or delete. This allows you to embed dynamic behavior directly into your container.
2277+
* ([Event-driven functions](#event-driven-functions)): triggered automatically in response to actions such as a document being created or an asset being uploaded.
2278+
* ([Callable functions](#callable-functions)): explicitly invoked from your frontend or from other services.
22822279

2283-
A naive schema representation of a hook that is triggered when a document is set:
2284-
2285-
![Functions hooks flow](/assets/images/functions-b7f754766a61062ffb5d9ebf5d8519a5.png)
2286-
2287-
### Asynchronous Hook Spawning
2280+
---
22882281

2289-
When a Function is triggered, it spawns hooks asynchronously, operating independently of the caller's action. This means that the execution of the hooks is initiated without waiting for a synchronous response, ensuring that the flow of update calls to the Satellite remains unhindered. Consequently, callers may receive feedback on their actions before the corresponding hooks have commenced their execution.
2282+
## Event-driven Functions
22902283

2291-
### Error-Resilient Execution
2284+
Event-driven functions respond to actions occurring in your Satellite. They are triggered automatically and never invoked directly.
22922285

2293-
Hooks are initiated only when there are no errors in the preceding operations. This ensures a robust and dependable execution flow, promoting reliability and consistency in the functioning of Functions.
2286+
### Hooks
22942287

2295-
### Optional
2288+
Hooks respond to specific actions within your Satellite. They run asynchronously, independently of the caller's request - meaning the caller may receive a response before the hook has finished executing.
22962289

2297-
Custom hooks are not active by default. You need to opt in to enable event-driven execution of your own logic.
2290+
![Functions hooks flow](/assets/images/functions-b7f754766a61062ffb5d9ebf5d8519a5.png)
22982291

2299-
---
2292+
**Note:**
23002293

2301-
## Available Hooks
2294+
Hooks are only initiated when the preceding operation completes without errors.
23022295

23032296
| Hook | Provider | Description |
23042297
| --- | --- | --- |
@@ -2314,11 +2307,9 @@ Custom hooks are not active by default. You need to opt in to enable event-drive
23142307
| `on_init` | Satellite | Called during the initialization of the Satellite. |
23152308
| `on_post_upgrade` | Satellite | Invoked after the Satellite has been upgraded to a new version. |
23162309

2317-
---
2318-
2319-
## Assertions
2310+
### Assertions
23202311

2321-
In addition to hooks, developers have the option to expand the native rule set of their Satellites by creating custom assertions. These assertions can be implemented similarly to hooks, with the key difference being that they are synchronous and must return a result indicating the outcome of the assertion.
2312+
Assertions run synchronously before an operation is executed. They allow you to validate or reject actions before any data is written.
23222313

23232314
| Assertion | Provider | Description |
23242315
| --- | --- | --- |
@@ -2329,6 +2320,21 @@ In addition to hooks, developers have the option to expand the native rule set o
23292320

23302321
---
23312322

2323+
## Callable Functions
2324+
2325+
Callable functions are explicitly invoked — from your frontend or from other services. They expose query and update endpoints directly from your Satellite.
2326+
2327+
**Tip:**
2328+
2329+
This is conceptually similar to exposing your own endpoints on an API.
2330+
2331+
| Type | Description |
2332+
| --- | --- |
2333+
| `query` | A read-only function that returns data without modifying state. |
2334+
| `update` | A function that can read and write state. |
2335+
2336+
---
2337+
23322338
## Rust vs. TypeScript
23332339

23342340
You can write serverless functions in either [Rust](/docs/build/functions/development/rust.md) or [TypeScript](/docs/build/functions/development/typescript.md), depending on your needs and project goals.
@@ -2569,11 +2575,17 @@ When you're ready to implement Functions within your Juno Satellite, you'll have
25692575

25702576
---
25712577

2572-
## Hooks
2578+
## Event-driven Functions
2579+
2580+
Event-driven functions respond to actions occurring in your Satellite. They are triggered automatically and never invoked directly.
2581+
2582+
---
2583+
2584+
### Hooks
25732585

25742586
Hooks allow you to define event-driven logic that responds to specific actions within your Satellite. The following is a list of available hooks and their respective use cases.
25752587

2576-
### on\_set\_doc
2588+
#### on\_set\_doc
25772589

25782590
Triggered when a document is created or updated in the datastore.
25792591

@@ -2588,7 +2600,7 @@ Triggered when a document is created or updated in the datastore.
25882600
export const onSetDoc = defineHook<OnSetDoc>({ collections: [], run: async (context) => { // Custom logic for handling document creation or updates }});
25892601
```
25902602

2591-
### on\_set\_many\_docs
2603+
#### on\_set\_many\_docs
25922604

25932605
Invoked for batch operations involving multiple document creations or updates.
25942606

@@ -2603,7 +2615,7 @@ Invoked for batch operations involving multiple document creations or updates.
26032615
export const onSetManyDocs = defineHook<OnSetManyDocs>({ collections: [], run: async (context) => { // Custom logic for handling multiple document creations or updates }});
26042616
```
26052617

2606-
### on\_delete\_doc
2618+
#### on\_delete\_doc
26072619

26082620
Invoked when a document is deleted from the datastore.
26092621

@@ -2618,7 +2630,7 @@ Invoked when a document is deleted from the datastore.
26182630
export const onDeleteDoc = defineHook<OnDeleteDoc>({ collections: [], run: async (context) => { // Custom logic for handling document deletion }});
26192631
```
26202632

2621-
### on\_delete\_many\_docs
2633+
#### on\_delete\_many\_docs
26222634

26232635
Used when multiple documents are deleted in a batch operation.
26242636

@@ -2633,7 +2645,7 @@ Used when multiple documents are deleted in a batch operation.
26332645
export const onDeleteManyDocs = defineHook<OnDeleteManyDocs>({ collections: [], run: async (context) => { // Custom logic for handling the deletion of multiple documents }});
26342646
```
26352647

2636-
### on\_delete\_filtered\_docs
2648+
#### on\_delete\_filtered\_docs
26372649

26382650
Invoked when documents are deleted according to specified filters in the datastore.
26392651

@@ -2648,7 +2660,7 @@ Invoked when documents are deleted according to specified filters in the datasto
26482660
export const onDeleteFilteredDocs = defineHook<OnDeleteFilteredDocs>({ collections: [], run: async (context) => { // Custom logic for handling the deletion of filtered documents }});
26492661
```
26502662

2651-
### on\_upload\_asset
2663+
#### on\_upload\_asset
26522664

26532665
Triggered during the process of uploading an asset.
26542666

@@ -2663,7 +2675,7 @@ Triggered during the process of uploading an asset.
26632675
export const onUploadAsset = defineHook<OnUploadAsset>({ collections: [], run: async (context) => { // Custom logic for handling asset uploads }});
26642676
```
26652677

2666-
### on\_delete\_asset
2678+
#### on\_delete\_asset
26672679

26682680
Activated when an asset is removed from the datastore.
26692681

@@ -2678,7 +2690,7 @@ Activated when an asset is removed from the datastore.
26782690
export const onDeleteAsset = defineHook<OnDeleteAsset>({ collections: [], run: async (context) => { // Custom logic for handling asset deletion }});
26792691
```
26802692

2681-
### on\_delete\_many\_assets
2693+
#### on\_delete\_many\_assets
26822694

26832695
Used for operations that involve deleting multiple assets in a batch.
26842696

@@ -2693,7 +2705,7 @@ Used for operations that involve deleting multiple assets in a batch.
26932705
export const onDeleteManyAssets = defineHook<OnDeleteManyAssets>({ collections: [], run: async (context) => { // Custom logic for handling the deletion of multiple assets }});
26942706
```
26952707

2696-
### on\_delete\_filtered\_assets
2708+
#### on\_delete\_filtered\_assets
26972709

26982710
Invoked when assets are deleted according to specified filters in the storage.
26992711

@@ -2708,7 +2720,7 @@ Invoked when assets are deleted according to specified filters in the storage.
27082720
export const onDeleteFilteredAssets = defineHook<OnDeleteFilteredAssets>({ collections: [], run: async (context) => { // Custom logic for handling the deletion of filtered assets }});
27092721
```
27102722

2711-
### on\_init
2723+
#### on\_init
27122724

27132725
* Rust
27142726
* TypeScript
@@ -2729,7 +2741,7 @@ This feature is not enabled by default. To use it, you’ll need to opt in by up
27292741

27302742
This hook is not available when writing functions in TypeScript.
27312743

2732-
### on\_post\_upgrade
2744+
#### on\_post\_upgrade
27332745

27342746
* Rust
27352747
* TypeScript
@@ -2752,11 +2764,11 @@ This hook is not available when writing functions in TypeScript.
27522764

27532765
---
27542766

2755-
## Assertions
2767+
### Assertions
27562768

27572769
Assertions enable validation checks before specific actions are executed within your Satellite. The following is a list of available assertions and their functionalities.
27582770

2759-
### assert\_set\_doc
2771+
#### assert\_set\_doc
27602772

27612773
Ensures a document can be created or updated.
27622774

@@ -2771,7 +2783,7 @@ Ensures a document can be created or updated.
27712783
export const assertSetDoc = defineAssert<AssertSetDoc>({ collections: [], assert: (context) => { // Custom logic for asserting a document's creation or update is possible // Throw an error if the condition fails to prevent the action }});
27722784
```
27732785

2774-
### assert\_delete\_doc
2786+
#### assert\_delete\_doc
27752787

27762788
Verifies that a document can be deleted.
27772789

@@ -2786,7 +2798,7 @@ Verifies that a document can be deleted.
27862798
export const assertDeleteDoc = defineAssert<AssertDeleteDoc>({ collections: [], assert: (context) => { // Custom logic for asserting a document can be deleted // Throw an error if the condition fails to prevent the action }});
27872799
```
27882800

2789-
### assert\_upload\_asset
2801+
#### assert\_upload\_asset
27902802

27912803
Confirms an asset upload can be committed.
27922804

@@ -2801,7 +2813,7 @@ Confirms an asset upload can be committed.
28012813
export const assertUploadAsset = defineAssert<AssertUploadAsset>({ collections: [], assert: (context) => { // Custom logic for asserting an asset upload is possible // Throw an error if the condition fails to prevent the action }});
28022814
```
28032815

2804-
### assert\_delete\_asset
2816+
#### assert\_delete\_asset
28052817

28062818
Checks that an asset can be deleted.
28072819

@@ -2818,7 +2830,7 @@ export const assertDeleteAsset = defineAssert<AssertDeleteAsset>({ collections:
28182830

28192831
---
28202832

2821-
## When the Functions Run
2833+
### When Hooks and Assertions Run
28222834

28232835
* Rust
28242836
* TypeScript
@@ -2848,6 +2860,42 @@ The `collections` attribute accepts a list of comma-separated collection names.
28482860

28492861
---
28502862

2863+
## Callable Functions
2864+
2865+
Callable functions (also referenced as custom functions) are explicitly invoked — from your frontend or from other canisters.
2866+
2867+
### Query
2868+
2869+
Defines a read-only function that returns data without modifying any state.
2870+
2871+
* Rust
2872+
* TypeScript
2873+
2874+
```
2875+
#[ic_cdk::query]fn my_function() -> String { // Your logic here}
2876+
```
2877+
2878+
```
2879+
export const myFunction = defineQuery({ args: Schema, returns: Schema, handler: ({ args }) => { // Your logic here return args; }});
2880+
```
2881+
2882+
### Update
2883+
2884+
Defines a function that can read and write state.
2885+
2886+
* Rust
2887+
* TypeScript
2888+
2889+
```
2890+
#[ic_cdk::update]fn my_function() -> String { // Your logic here}
2891+
```
2892+
2893+
```
2894+
export const myFunction = defineUpdate({ args: Schema, returns: Schema, handler: async ({ args }) => { // Your logic here return args; }});
2895+
```
2896+
2897+
---
2898+
28512899
## Further Resources
28522900

28532901
* Rust

blog/2025-04-09-data-validation-in-juno-best-practices-and-security.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ Remember: Security is about preventing unauthorized or invalid operations, not j
486486
## References
487487

488488
- [Deep Dive into Serverless Functions](/docs/build/functions/)
489-
- [Available Hooks](/docs/build/functions/#available-hooks)
489+
- [Available Hooks](/docs/build/functions/development/#hooks)
490490
- [List of Assertions](/docs/build/functions/#assertions)
491491
- [Examples of Writing Functions in Rust](/docs/guides/rust)
492492

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Defines a read-only function that returns data without modifying any state.
2+
3+
import Tabs from "@theme/Tabs";
4+
import TabItem from "@theme/TabItem";
5+
6+
```mdx-code-block
7+
<Tabs groupId="functions">
8+
<TabItem value="Rust">
9+
```
10+
11+
```rust
12+
#[ic_cdk::query]
13+
fn my_function() -> String {
14+
// Your logic here
15+
}
16+
```
17+
18+
```mdx-code-block
19+
</TabItem>
20+
<TabItem value="TypeScript">
21+
```
22+
23+
```typescript
24+
export const myFunction = defineQuery({
25+
args: Schema,
26+
returns: Schema,
27+
handler: ({ args }) => {
28+
// Your logic here
29+
return args;
30+
}
31+
});
32+
```
33+
34+
```mdx-code-block
35+
</TabItem>
36+
</Tabs>
37+
```
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Defines a function that can read and write state.
2+
3+
import Tabs from "@theme/Tabs";
4+
import TabItem from "@theme/TabItem";
5+
6+
```mdx-code-block
7+
<Tabs groupId="functions">
8+
<TabItem value="Rust">
9+
```
10+
11+
```rust
12+
#[ic_cdk::update]
13+
fn my_function() -> String {
14+
// Your logic here
15+
}
16+
```
17+
18+
```mdx-code-block
19+
</TabItem>
20+
<TabItem value="TypeScript">
21+
```
22+
23+
```typescript
24+
export const myFunction = defineUpdate({
25+
args: Schema,
26+
returns: Schema,
27+
handler: async ({ args }) => {
28+
// Your logic here
29+
return args;
30+
}
31+
});
32+
```
33+
34+
```mdx-code-block
35+
</TabItem>
36+
</Tabs>
37+
```

0 commit comments

Comments
 (0)