Skip to main content

Instance methods

createSafeActionClient creates an instance of the safe action client, which has the following methods:

use

use<NextCtx>(middlewareFn: MiddlewareFn<ServerError, Ctx, NextCtx, Metadata>) => new SafeActionClient()

use accepts a middleware function of type MiddlewareFn as argument and returns a new instance of the safe action client with that middleware function added to the stack, that will be executed after the last one, if any. Check out how to use middleware in the related section of the usage guide.

metadata

metadata(data: Metadata) => { schema() }

metadata expects an argument of the same type as the return value of the defineMetadataSchema optional initialization function. If you don't provide this function to the action client when you initialize it, metadata will be undefined.

metadata lets you specify useful data about the safe action you're executing. If you don't use this method before defining your action (using action method), metadata will be undefined inside serverCodeFn. It returns the schema method, since metadata is action specific and not shared with other actions. You can then access it in the middlewareFn passed to use and in serverCodeFn passed to action.

schema

schema<S extends Schema | undefined = undefined, FVE = ValidationErrors<S>, MD = null>(schema: S, { utils?: { formatValidationErrors?: FormatValidationErrorsFn<S, FVE> } }) => { action(), bindArgsSchemas() }

schema accepts an optional input schema of type Schema (from TypeSchema) and an optional utils object that accepts a formatValidationErrors function. The schema is used to define the arguments that the safe action will receive, the optional formatValidationErrors function is used to return a custom format for validation errors. If you don't pass an input schema, parsedInput and validation errors will be typed undefined, and clientInput will be typed void. It returns the action and bindArgsSchemas methods, which allows you, respectively, to define a new action using that input schema or extend the arguments with additional bound ones.

bindArgsSchemas

bindArgsSchemas<const BAS extends Schema[], FBAVE = BindArgsValidationErrors<BAS>>(bindArgsSchemas: BAS, bindArgsUtils?: { formatBindArgsValidationErrors?: FormatBindArgsValidationErrorsFn<BAS, FBAVE> }) => { action() }

bindArgsSchemas accepts an array of bind input schemas of type Schema[] (from TypeSchema) and an optional bindArgsUtils object that accepts a formatBindArgsValidationErrors function. The schema is used to define the bind arguments that the safe action will receive, the optional formatBindArgsValidationErrors function is used to return a custom format for bind arguments validation errors. It returns the action method, which allows you, to define a new action using the input and bind inputs schemas.

action / stateAction

action<Data>(serverCodeFn: ServerCodeFn<S, BAS, Data, Ctx, MD>) => SafeActionFn<ServerError, S, BAS, FVE, FBAVE, Data>
stateAction<Data>(serverCodeFn: StateServerCodeFn<ServerError, S, BAS, FVE, FBAVE, Ctx, MD, Data>) => SafeStateActionFn<ServerError, S, BAS, FVE, FBAVE, Data> 

action/stateAction is the final method in the list. It accepts a serverCodeFn of type ServerCodeFn/StateServerCodeFn and returns a new safe action function of type SafeActionFn/SafeStateActionFn, which can be called from your components. When an action doesn't need input arguments, you can directly use this method without passing a schema to schema method.

When the action is executed, all middleware functions in the chain will be called at runtime, in the order they were defined.

When to use action or stateAction

The only difference between action and stateAction is that useStateAction hook requires you to use stateAction when defining a new Server Action function. Using stateAction changes the function signature: the first argument of the safe action will be prevResult, and the second one the client input, if a validation schema was passed to schema method.

Note that when you use stateAction, and you also want to access prevResult in serverCodeFn, you must type the returned data type of the function, since it can't be inferred, due to TypeScript limitations. You can see an example of this in the useStateAction usage example section.

serverCodeFn

Stateless action
serverCodeFn<S, BAS, Data, Ctx, MD> = (args: {
parsedInput: S extends Schema ? Infer<S> : undefined;
bindArgsParsedInputs: InferArray<BAS>;
ctx: Ctx;
metadata: MD;
}) => Promise<Data>;
Stateful action
serverCodeFn<ServerError, S extends Schema | undefined, BAS extends readonly Schema[], FVE, FBAVE, Ctx, MD, Data> = (
args: {
parsedInput: S extends Schema ? Infer<S> : undefined;
bindArgsParsedInputs: InferArray<BAS>;
ctx: Ctx;
metadata: MD;
},
utils: { prevResult: Prettify<SafeActionResult<ServerError, S, BAS, FVE, FBAVE, Data>> }
) => Promise<Data>;

serverCodeFn is the async function that will be executed on the server side when the action is invoked. If input validation fails, or execution gets halted in a middleware function, the server code function will not be called.

In the case of a stateful safe action, serverCodeFn will also receive the prevResult as a property of the second argument (utils object) from the previous action execution, thanks to the useStateAction hook (that uses React's useActionState hook under the hood).