Skip to main content
MediaKit

createCaller

AuthPC was renamed to pRPC

Use this method to interact with the api, you can choose between a query or a mutation (default is query) and also choose to use either GET/POST as the request method (default is GET & wrapped with Solid's query function).

API

No Schema

server.ts
import { createCaller } from '@solid-mediakit/prpc'
const myServerQuery = createCaller(
({ session$ }) => {
console.log(session$, event$.request.headers.get('user-agent'))
return 'Who do i say hey to'
},
{
method: 'GET',
},
)
// client.tsx
import { myServerQuery } from './server'
const query = myServerQuery()

Zod

server.ts
import { createCaller } from '@solid-mediakit/prpc'
import { z } from 'zod'
const mySchema = z.object({ name: z.string() })
export const myServerQuery = createCaller(
mySchema,
({ input$, session$, event$ }) => {
console.log(session$, event$.request.headers.get('user-agent'))
return `Hey there ${input$.name}`
},
{
method: 'GET',
},
)
// client.tsx
import { myServerQuery } from './server'
const query = myServerQuery(() => ({ name: 'Demo' }))

Valibot

server.ts
import { createCaller } from '@solid-mediakit/prpc'
import * as v from 'valibot'
const mySchema = v.object({ name: v.string() })
export const myServerQuery = createCaller(
mySchema,
({ input$, session$, event$ }) => {
console.log(session$, event$.request.headers.get('user-agent'))
return `Hey there ${input$.name}`
},
{
method: 'GET',
},
)
// client.tsx
import { myServerQuery } from './server'
const query = myServerQuery(() => ({ name: 'Demo' }))

Error Handling

Errors are thrown using the PRPClientError class. When the server function has a schema defined, you can use the isValidationError to get the issues.

import { createEffect } from 'solid-js'
import { myServerQuery } from './server'
const MyClient = () => {
const query = myServerQuery(() => ({ name: 'Demo' }))
createEffect(() => {
if (query.error) {
if (query.error.isValidationError()) {
query.error.cause.fieldErrors.name // string[]
} else {
console.error('What is this', query.error.cause)
}
}
})
return (...)
}
export default MyClient

Methods

You can choose any method (GET || POST), regardless of the function type (default is GET & wrapped with Solid's query function)

GET

This is the default so you don't have to mention it

import { createCaller, response$ } from '@solid-mediakit/prpc'
export const getRequest = createCaller(
() => {
return response$(
{ iSetTheHeader: true },
{ headers: { 'cache-control': 'max-age=60' } },
)
},
{
method: 'GET',
},
)
export const getRequest2 = createCaller(() => {
return response$(
{ iSetTheHeader: true },
{ headers: { 'cache-control': 'max-age=60' } },
)
})
export const protectedQuery = createCaller(
({ session$ }) => {
console.log(session$.user)
return `Hey there ${session$.user.name}`
},
{
protected: true,
},
)

POST

You can also use POST with queries. When using mutations / actions you don't have to specify the method and the default will be POST

import { createCaller, response$ } from '@solid-mediakit/prpc'
export const postRequest = createCaller(
() => {
return response$({ iSetTheHeader: true }, { headers: { 'X-Testing': '1' } })
},
{
method: 'POST',
},
)
export const postRequest2 = createCaller(
() => {
return response$({ iSetTheHeader: true }, { headers: { 'X-Testing': '1' } })
},
{
type: 'action',
},
)

Function Types

In addition to methods, you can also choose a function type (the function type will not affect the request method).

query

This is the default, you don't have to specify this:

import { createCaller } from '@solid-mediakit/prpc'
const thisIsAQuery = createCaller(() => {
return 1
})
const alsoIsAQuery = createCaller(
() => {
return 1
},
{
type: 'query',
},
)
// client side
const query = thisIsAQuery()
query.data // number

mutation

You can either specify {type: 'action'} or use the createAction method

import { createCaller, createAction } from '@solid-mediakit/prpc'
const thisIsAMutation = createCaller(
() => {
return 1
},
{
type: 'action',
},
)
const alsoIsAMutation = createAction(() => {
return 1
})
// client side
const mutation = thisIsAMutation()
mutation.mutate()

Middlewares & .use

This method allows you create a reuseable caller that contains your middlewares. You can combine multiple callers / middlewares and import them to different files, take a look at this example.

file1.ts

In this file we create a caller with a custom middleware and then export it so it could be use in other files as-well.

import { createCaller } from '@solid-mediakit/prpc'
export const withMw1 = createCaller.use(() => {
return {
myFile1: 1,
}
})
export const action1 = withMw1(({ ctx$ }) => {
return `hey ${ctx$.myFile1} `
})

This Transforms To

file2.ts

In this file we can actually import the caller we created and then add more middlewares to it or use it as is.

import { withMw1 } from './file1'
export const withMw2 = withMw1.use(({ ctx$ }) => {
return {
...ctx$,
myFile2: 2,
}
})
export const action2 = withMw2(({ ctx$ }) => {
return `hey ${ctx$.myFile1} ${ctx$.myFile2}`
})

Utils

pRPC contains many utils out of the box, like redirection, erroring, setting cookies, etc.

redirect$

Use this function to redirect the user (this will not affect the function type):

import { createCaller, redirect$ } from '@solid-mediakit/prpc'
let redirect = false
export const myQuery = createCaller(() => {
if (redirect) {
return redirect$('/login')
}
return 'yes'
})

error$

Use this function to throw an error on the user side (this will not affect the function type):

import { createCaller, error$ } from '@solid-mediakit/prpc'
let shouldError = false
export const myQuery = createCaller(() => {
if (shouldError) {
return error$('Why did i error')
}
return 'yes'
})

response$

Use this function to return data & modify headers (the return type is also infered from the data passed to response$):

import { createCaller, response$ } from '@solid-mediakit/prpc'
let setHeader = false
export const myQuery = createCaller(() => {
if (setHeader) {
return response$(1, {
headers: { this: 'that' },
})
}
return 'yes'
})
// respone type: number | string

Optimistic Updates

Similiar to tRPC, each query function has a useUtils method, so lets say we import a server action we created using createCaller called serverQuery1

import { serverQuery1, serverMutation1 } from '~/server/etc'
const MyComponent = () => {
const listPostQuery = serverQuery1()
const serverQueryUtils = serverQuery1.useUtils()
const postCreate = serverMutation1(() => ({
async onMutate(newPost) {
// Cancel outgoing fetches (so they don't overwrite our optimistic update)
await serverQueryUtils.cancel()
// Get the data from the queryCache
const prevData = serverQueryUtils.getData()
// Optimistically update the data with our new post
serverQueryUtils.setData(undefined, (old) => [...old, newPost])
// Return the previous data so we can revert if something goes wrong
return { prevData }
},
onError(err, newPost, ctx) {
// If the mutation fails, use the context-value from onMutate
serverQueryUtils.setData(undefined, ctx.prevData)
},
onSettled() {
// Sync with server once mutation has settled
serverQueryUtils.invalidate()
},
}))
}

raw

Each function has function.raw which is the transformed server function.

import { createCaller } from '@solid-mediakit/prpc'
const fn = createCaller(() => 1)
const callFn = async () => await fn.raw() // number

createAsync

Having this, we can ofc use Solid's built in createAsync

import { createAsync } from '@solidjs/router'
const myAsyncSignal = createAsync(() => fn.raw(), { deferStream: true })

Last updated: 5/30/25, 9:16 AM

MediaKitFully featured, fully customisable static site generation for SolidStart
Community
github