Jac Serve Command#
The jac serve
command turns your Jac programs into authenticated REST APIs automatically.
Overview#
When you run jac serve
, it:
1. Executes your target Jac module
2. Converts all functions into REST API endpoints with introspected signatures
3. Converts all walkers into REST APIs where:
- Walker fields (has variables) become the API interface
- An additional target_node
field specifies where to spawn the walker
4. Creates a user management system where each user has their own persistent root node
5. Requires authentication via token-based auth for all protected endpoints
Usage#
# Basic usage
jac serve myprogram.jac
# Specify a custom port
jac serve myprogram.jac --port 8080
# Use a specific session file for persistence
jac serve myprogram.jac --session myapp.session
API Endpoints#
Public Endpoints (No Authentication Required)#
GET /#
Returns API information and available endpoints.
Example:
POST /user/create#
Create a new user account. Each user gets their own persistent root node.
Request Body:
Response:
Example:
curl -X POST http://localhost:8000/user/create \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "secret123"}'
POST /user/login#
Authenticate and receive a token.
Request Body:
Response:
Example:
curl -X POST http://localhost:8000/user/login \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "secret123"}'
Protected Endpoints (Authentication Required)#
All protected endpoints require an Authorization
header with a Bearer token:
GET /functions#
List all available functions in the module.
Example:
Response:
GET /function/#
Get the signature and parameter information for a specific function.
Example:
Response:
{
"name": "add_numbers",
"signature": {
"parameters": {
"a": {
"type": "int",
"required": true,
"default": null
},
"b": {
"type": "int",
"required": true,
"default": null
}
},
"return_type": "int"
}
}
POST /function/#
Call a function with the provided arguments.
Request Body:
Response:
Example:
curl -X POST http://localhost:8000/function/add_numbers \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"args": {"a": 5, "b": 10}}'
GET /walkers#
List all available walkers in the module.
Example:
Response:
GET /walker/#
Get the field information for a specific walker.
Example:
Response:
{
"name": "CreateTask",
"info": {
"fields": {
"title": {
"type": "str",
"required": true,
"default": null
},
"priority": {
"type": "int",
"required": false,
"default": "1"
},
"target_node": {
"type": "str (node ID, optional)",
"required": false,
"default": "root"
}
}
}
}
POST /walker/#
Spawn a walker with the provided fields.
Request Body:
Response:
Example:
curl -X POST http://localhost:8000/walker/CreateTask \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"fields": {"title": "Buy groceries", "priority": 2}}'
Complete Workflow Example#
Here's a complete example using the example_api.jac
file:
1. Start the server#
2. Create a user#
TOKEN=$(curl -s -X POST http://localhost:8000/user/create \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "secret123"}' \
| jq -r '.token')
echo "Token: $TOKEN"
3. Call a function#
curl -X POST http://localhost:8000/function/add_numbers \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"args": {"a": 15, "b": 27}}'
4. Create tasks using walkers#
# Create first task
curl -X POST http://localhost:8000/walker/CreateTask \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"fields": {"title": "Buy groceries", "priority": 2}}'
# Create second task
curl -X POST http://localhost:8000/walker/CreateTask \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"fields": {"title": "Write documentation", "priority": 1}}'
5. List all tasks#
curl -X POST http://localhost:8000/walker/ListTasks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"fields": {}}'
6. Complete a task#
curl -X POST http://localhost:8000/walker/CompleteTask \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"fields": {"title": "Buy groceries"}}'
Persistence#
- Each user has their own persistent root node stored in the session file
- All nodes created by a user are attached to their root and persist across API calls
- The session file stores the graph structure and can be reused across server restarts
- Different users have isolated graph spaces - they cannot access each other's nodes
Authentication#
- Token-based authentication using Bearer tokens
- Tokens are generated during user creation and login
- All protected endpoints (functions and walkers) require a valid token
- Each request executes in the context of the authenticated user's root node
Key Features#
- Automatic API Generation: Functions and walkers automatically become REST endpoints
- Type Introspection: Function signatures are analyzed to generate API documentation
- User Isolation: Each user has their own persistent root and graph space
- Session Persistence: User data persists across server restarts via session files
- Standard Library Only: Uses only Python standard libraries (http.server, json, hashlib, etc.)
- CORS Support: Includes CORS headers for web application integration
Notes#
- The
target_node
field for walkers is optional and defaults to the user's root node - If
target_node
is specified, it should be a valid node ID (hex string) - All walker execution happens in the context of the authenticated user
- The server binds to
0.0.0.0
by default, making it accessible on all network interfaces