Skip to Content
DocsCore ConceptsCreating Procedures

Creating Procedures

Procedures in Actyx RPC are constructed using a procedure builder created by createProcedure(). This allows you to encapsulate and reuse shared server concerns, such as authentication, logging, global context, and centralized error mapping.

createProcedure()

To get started, instantiate a base procedure builder:

import { createProcedure } from "@explita/actyx-rpc"; const procedure = createProcedure({ async createContext() { const session = await getSession(); if (!session) { return { ok: false, reason: "UNAUTHORIZED" }; } return { ok: true, ctx: { userId: session.user.id, role: session.user.role, }, }; }, onContextError({ reason }) { if (reason === "UNAUTHORIZED") { return { _redirect: () => redirect("/login"), message: "Session expired or invalid", }; } }, onSuccess({ ctx, input, output, duration }) { console.log("Procedure completed successfully", { handler: ctx.handlerName, duration }); }, inputMode: "strict", // "strict" | "form" | "partial" });

Configuration Options

OptionTypeDescription
createContext(prev) => Promise<ContextResult>Runs at the start of the request lifecycle to generate a shared context. Can return { ok: false, reason: string } on failure.
onContextError(err) => anyCalled if createContext fails. Useful for global redirects or constructing unified error payloads.
enrichInput(ctx) => Promise<TEnrich> | TEnrichRuns after context creation to attach global context keys (e.g., userId) into all procedure input objects.
onSuccess(props) => voidRuns when a procedure finishes successfully. Receives context, input, output, and execution duration.
onError(props) => anyRuns when a procedure throws or returns an error. Returns mapped error format.
inputModeInputModeThe default caller input mode for procedures (strict, form, partial).
middlewaresMiddleware[]Array of global middlewares applied to all procedures generated from this builder.
pluginsPlugin[]Array of global plugins applied to all procedures.
cacheCacheAdapterThe global cache adapter used for caching queries and rate-limit tracking (defaults to MemoryCache).
compressionCompressorThe global compressor instance used for response compression (defaults to Compressor).
metaTMetaDefault global metadata attached to all child procedures.

Global Error Mapping

The onError hook is a powerful way to centralize error handling. Instead of polluting every query or mutation handler with identical try/catch blocks, let your handlers throw naturally.

When onError returns an object, that object becomes the official error response returned by the procedure to the client.

const procedure = createProcedure({ // ... onError({ error, ctx }) { // If the procedure has a .name("..."), it's available in ctx.handlerName console.error(`Error in ${ctx.handlerName}:`, error); // Map database unique constraint violations globally if (error.code === "P2002") { return { success: false, message: "Conflict detected", reason: "VALIDATION_ERROR", errors: { [error.meta.target[0]]: "This value is already taken", }, }; } }, });

Now your actual query and mutation handlers can be clean and free of boilerplate:

const createUser = procedure.input(userResolver).mutation(async ({ input }) => { // Just throw! No try/catch needed here. return await db.user.create({ data: input }); });

Next.js Redirects in Context Failures

If you are using Next.js, you can return a _redirect callback in onContextError (or inside middlewares) to trigger a top-level redirect:

onContextError({ reason }) { if (reason === "INVALID_SESSION") { return { _redirect: () => redirect("/login"), message: "Session expired", }; } }

This is executed at the very start of the procedure response before returning to the caller.

Last updated on