Skip to main content

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

  1. Include server function source files in your deploy’s source_files map
  2. Files under api/ become HTTP endpoints at /functions/
  3. Canvas transpiles TypeScript → JavaScript via esbuild and executes your handler in a sandboxed async context
Source fileEndpoint
api/hello.tsGET/POST /functions/hello
api/search.jsGET/POST /functions/search
api/data/export.tsGET/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:
PropertyTypeDescription
ctx.req.methodstringHTTP method (GET, POST, etc.)
ctx.req.pathstringRequest path
ctx.req.queryobjectURL query parameters
ctx.req.bodyanyParsed JSON body (for POST/PUT)
ctx.req.headersobjectRequest headers (excluding internal headers)
ctx.envobjectApp environment variables
ctx.kvobjectKey-value store (see below)

Return value

Return an object with:
FieldTypeDefaultDescription
statusnumber200HTTP status code
bodyanyResponse body (object → JSON, string → text)
headersobject{}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 },
  }
}
MethodSignatureDescription
getkv.get(key: string): Promise<string | null>Read a value
setkv.set(key: string, value: string, ttl?: number): Promise<void>Write a value (optional TTL in seconds, default 30 days)
delkv.del(key: string): Promise<void>Delete a key
keyskv.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)