External RPCs
External RPCs let external clients invoke your Pikku functions via HTTP POST endpoints (and channels on roadmap).
Exposing Functions​
Functions with expose: true can be called by external systems:
export const calculateOrderTotal = pikkuSessionlessFunc<
{ items: Array<{ price: number; quantity: number }> },
{ subtotal: number; tax: number; total: number }
>({
func: async ({ database }, data) => {
const subtotal = data.items.reduce(
(sum, item) => sum + (item.price * item.quantity),
0
)
const taxRate = await database.query('config', {
where: { key: 'tax_rate' }
})
const tax = subtotal * (taxRate?.value ?? 0.08)
return { subtotal, tax, total }
},
expose: true, // Can be called externally
docs: {
summary: 'Calculate order totals with tax',
tags: ['orders']
}
})
Everything else is derived from the function:
- Input validation from your types
- Authentication from
authsetting (default:true) - Permissions from
permissionsproperty - Error responses from thrown errors
See Authentication for auth configuration.
Wiring an RPC Endpoint​
Wire an HTTP endpoint that calls any exposed function:
import { wireHTTP } from './pikku-types.gen.js'
import { pikkuSessionlessFunc } from './pikku-types.gen.js'
// Generic RPC caller function
export const rpcCaller = pikkuSessionlessFunc<
{ name: string; data: unknown },
unknown
>({
func: async ({ rpc }, { name, data }) => {
return await rpc.invokeExposed(name, data)
},
docs: {
summary: 'Call any exposed function via RPC',
tags: ['rpc']
}
})
// Wire it to HTTP
wireHTTP({
method: 'post',
route: '/rpc',
func: rpcCaller
})
External clients call it:
POST /rpc
Content-Type: application/json
{
"name": "calculateOrderTotal",
"data": {
"items": [
{ "price": 10, "quantity": 2 },
{ "price": 15, "quantity": 1 }
]
}
}
Response:
{
"subtotal": 35,
"tax": 2.8,
"total": 37.8
}
Type-Safe Client​
Pikku generates a type-safe client for calling external RPCs:
import { pikkuClient } from './pikku-fetch.gen.js'
const client = pikkuClient('https://api.example.com')
// Fully type-safe RPC calls
const totals = await client.calculateOrderTotal({
items: [
{ price: 10, quantity: 2 },
{ price: 15, quantity: 1 }
]
})
console.log(totals.subtotal) // TypeScript knows the return type
The client:
- Enforces correct input types
- Knows exact output types
- Handles authentication
- Formats errors appropriately
See Fetch Client for details.
Next Steps​
- Internal RPCs - Function-to-function calls
- Fetch Client - Type-safe HTTP client
- Functions - Understanding Pikku functions