Documentation Index
Fetch the complete documentation index at: https://docs.mixpeek.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Server functions let you run backend logic inside your Canvas app. Write TypeScript or JavaScript handlers that execute server-side with access to environment variables, a built-in KV store, and fetch — without managing infrastructure.
How it works
- Include server function source files in your deploy’s
source_files map
- Files under
api/ become HTTP endpoints at /functions/
- Canvas transpiles TypeScript → JavaScript via esbuild and executes your handler in a sandboxed async context
| Source file | Endpoint |
|---|
api/hello.ts | GET/POST /functions/hello |
api/search.js | GET/POST /functions/search |
api/data/export.ts | GET/POST /functions/data/export |
Writing a server function
Export a default function that receives a context object and returns a response:
// api/hello.ts
export default async function handler(ctx) {
const name = ctx.req.query.name || 'world'
return {
status: 200,
body: { message: `Hello, ${name}!` },
}
}
Context object
Your handler receives a ctx object with:
| Property | Type | Description |
|---|
ctx.req.method | string | HTTP method (GET, POST, etc.) |
ctx.req.path | string | Request path |
ctx.req.query | object | URL query parameters |
ctx.req.body | any | Parsed JSON body (for POST/PUT) |
ctx.req.headers | object | Request headers (excluding internal headers) |
ctx.env | object | App environment variables |
ctx.kv | object | Key-value store (see below) |
Return value
Return an object with:
| Field | Type | Default | Description |
|---|
status | number | 200 | HTTP status code |
body | any | — | Response body (object → JSON, string → text) |
headers | object | {} | Custom response headers |
Key-value store
Every app has a built-in Redis-backed KV store, accessible in server functions via ctx.kv:
// api/counter.ts
export default async function handler(ctx) {
const current = await ctx.kv.get('visit_count')
const count = parseInt(current || '0') + 1
await ctx.kv.set('visit_count', String(count))
return {
body: { visits: count },
}
}
| Method | Signature | Description |
|---|
get | kv.get(key: string): Promise<string | null> | Read a value |
set | kv.set(key: string, value: string, ttl?: number): Promise<void> | Write a value (optional TTL in seconds, default 30 days) |
del | kv.del(key: string): Promise<void> | Delete a key |
keys | kv.keys(): Promise<string[]> | List all keys for this app |
Calling the Mixpeek API
Use fetch to call the Mixpeek API through the Canvas proxy — credentials are injected automatically:
// api/search.ts
export default async function handler(ctx) {
const { query } = ctx.req.body
const res = await fetch('https://api.mixpeek.com/v1/retrievers/ret_abc123/execute', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${ctx.env.MIXPEEK_API_KEY}`,
'X-Namespace': ctx.env.MIXPEEK_NAMESPACE_ID,
},
body: JSON.stringify({ inputs: { query }, settings: { limit: 10 } }),
})
return { body: await res.json() }
}
Deploying with source files
Include your server functions in the source_files field when deploying:
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/deploy \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "cli_upload",
"bundle_s3_key": "$BUNDLE_KEY",
"environment": "production",
"message": "Add search API route",
"source_files": {
"api/hello.ts": "export default async function handler(ctx) {\n return { body: { message: \"Hello!\" } }\n}",
"api/search.ts": "export default async function handler(ctx) {\n // search logic here\n}"
}
}'
Runtime logging
console.log, console.warn, console.error, and console.info calls in server functions are captured and sent to the runtime logs system. View them in Studio or query via API.
// api/process.ts
export default async function handler(ctx) {
console.log('Processing request', ctx.req.method, ctx.req.path)
try {
const result = await doWork(ctx.req.body)
console.info('Success:', result.id)
return { body: result }
} catch (err) {
console.error('Failed:', err.message)
return { status: 500, body: { error: err.message } }
}
}
Limitations
- Execution timeout: 30 seconds per request
- Request body size: 1 MB max
- No filesystem access: Server functions run in a sandboxed context
- No npm imports: Only
fetch and the ctx APIs are available in the execution context
- TypeScript only:
.ts and .js files are supported (transpiled via esbuild)