API Routes
Capela automatically generates API routes for your application, allowing you to interact with it through a RESTful API.
Overview
Capela provides two main types of API routes:
- Function Routes (
/d/): Call functions on your application - State Routes (
/g/): Fetch and modify state variables from your application
Function Routes (/d/)
Function routes let you call functions on your application:
http POST 'http://localhost:22440/d/!partition_id/function_name' param1=value1 param2=value2
Example
# Call the say_hello_to function
http POST 'http://localhost:22440/d/!partition_id/say_hello_to' name="Alice"
Parameters
Parameters are passed as query parameters in the URL. The parameter names must match the parameter names in your function definition.
def say_hello_to(self, name: str):
this.count += 1
return f"Hello, {name}! The count is: {this.count}"
In this example, the parameter name is name, so the API call would be:
http POST 'http://localhost:22440/d/!partition_id/say_hello_to' name="Alice"
Return Values
Function routes return the return value of the function. In the example above, the return value would be:
"Hello, Alice! The count is: 1"
State Routes (/g/)
State routes let you fetch and modify state variables from your application:
# GET state
http GET 'http://localhost:22440/g/!partition_id/variable_name'
# POST state
http POST 'http://localhost:22440/g/!partition_id/variable_name' --raw value
Example
# Fetch the count variable
http GET 'http://localhost:22440/g/!partition_id/count'
# Set a value in a dictionary
http POST 'http://localhost:22440/g/!partition_id/exampleDict/"new_key"' --raw 5
# Set a value in an array
http POST 'http://localhost:22440/g/!partition_id/exampleArray/0' --raw "new_value"
Content-Location Headers
All responses include a content-location header that provides the canonical path to the accessed item. For example:
content-location: /!acb01737d7434a3877089e5cdcbe122b739c2c9cf529349f468bae1fb5a20be1/%0
You can use either:
- The full path with
%0notation - The human-readable path (e.g.,
/go/to/path)
Nested Variables
You can access nested variables using dot notation or array notation:
# Fetch a nested variable
http GET 'http://localhost:22440/g/!partition_id/users/Alice/name'
# Set a nested variable
http POST 'http://localhost:22440/g/!partition_id/users/Alice/name' --raw "Bob"
Collection Variables
You can access collection variables using array notation or quoted keys for dictionaries:
# Fetch a collection variable
http GET 'http://localhost:22440/g/!partition_id/users'
# Set a dictionary value
http POST 'http://localhost:22440/g/!partition_id/users/"Alice"' --raw '{"name": "Alice", "age": 30}'
# Set an array value
http POST 'http://localhost:22440/g/!partition_id/users/0' --raw '{"name": "Alice", "age": 30}'
WebSocket SDK
The WebSocket SDK provides a more efficient way to interact with your application's state, especially for frontend applications. It offers real-time updates, automatic reconnection, and efficient caching.
For detailed information about the WebSocket SDK, including features, best practices, and examples, see the WebSocket SDK documentation.
Basic usage example:
import { getValue, setValue, subscribe } from 'capela-sdk';
// Get a value
const value = await getValue("!partition_id/variable_name");
// Set a value
await setValue("!partition_id/variable_name", new_value);
// Subscribe to changes
const unsubscribe = subscribe("!partition_id/variable_name", (newValue) => {
console.log("Value changed:", newValue);
});
// Later, when you want to stop listening:
unsubscribe();
Example: User Manager
Here's a simple example of an application that uses API routes:
from builtins import Node, Field, Dict, List
class User(Node):
name: str = Field(default="")
age: int = Field(default=0)
is_active: bool = Field(default=True)
def activate(self):
this.is_active = True
return this.is_active
def deactivate(self):
this.is_active = False
return this.is_active
class UserManager(Node):
users: Dict[str, User] = Field(default_factory=dict)
def register_user(self, user_name: str, age: int) -> User:
if user_name not in this.users:
user = User(name=user_name, age=age)
this.users[user_name] = user
return user
return this.users[user_name]
def get_user(self, user_name: str) -> User:
if user_name in this.users:
return this.users[user_name]
return None
def list_users(self) -> List[str]:
return list(this.users.keys())
To use this application:
-
Deploy the application:
capelac deploy apps/user_manager -
Create a partition:
http POST 'http://localhost:22440/partitions' object_type=ai.asmc.user_manager.UserManager -
Use the API routes:
# Register a user
http POST 'http://localhost:22440/d/!partition_id/register_user' user_name="Alice" age=30
# Get a user
http GET 'http://localhost:22440/g/!partition_id/users/Alice'
# List users
http GET 'http://localhost:22440/g/!partition_id/users'
# Activate a user
http POST 'http://localhost:22440/d/!partition_id/users/Alice/activate'
# Deactivate a user
http POST 'http://localhost:22440/d/!partition_id/users/Alice/deactivate'