Nextjs server action issue
in the form:
type Ingredient = {
name: string;
purchasePrice: Prisma.Decimal;
}
const onSubmit = async (values: Ingredient) => {
await addIngredient(values)
}
in the ingredient-actions.ts file:
export const addIngredient = async (ingredientData: Ingredient ): Promise<IngredientPrisma | ErrorMessage> => {
try {
const ingredientResponse = await prisma.ingredient.create({ data: {
name: ingredientData.name,
purchasePrice: ingredientData.purchasePrice,
} });
revalidatePath('/dashboard');
return ingredientResponse;
} catch (err) {
return {
message: 'Error creating ingredient'
}
}
}
and I'm having an error ("Only plain objects can be passed to Server Functions"),
so meanwhile I'm "fixing" this by doing addIngredient(JSON.stringify(values))
in the onSubmit
.
and in the definition of the action, undo by doing JSON.parse(ingredientData)
.
export const addIngredient = async (ingredientData: string): Promise<IngredientPrisma | ErrorMessage> => {
try {
const ingredient:Ingredient = JSON.parse(ingredientData);
const ingredientResponse = await prisma.ingredient.create({ data: {
name: ingredient.name,
purchasePrice: ingredient.purchasePrice,
} });
revalidatePath('/dashboard');
return ingredientResponse;
} catch (err) {
return {
message: 'Error creating ingredient'
}
}
}
how would you deal with that without using JSON ?
As the error indicates, plain objects are allowed without having to convert them to a JSON-string first. That means that stuff like functions are not allowed (since functions cannot be serialized and sent to the server). However a Prisma.Decimal
is not a plain object, nor an array nor a primitive (like a string, number or boolean).
Peeking into the Prisma docs, we find that:
Decimal fields are represented by the
Decimal.js
library.
That library constructs "class" (in quotes because JS doesn't technically have classes and they are just syntax-sugar for prototype-based inheritance) instances which can (and in case of decimal.js do) have instance functions which cannot be serialized.
First of all, I am not sure if this is a compiler / linter warning or an actual runtime warning. Regardless of whether it's a compiler / linter warning, it might suffice to change the typing of Ingredient
to this:
type Ingredient = {
name: string;
purchasePrice: number;
}
This should also be more accurate since your frontend should not have a "concept" of Prisma.
The lines between frontend and backend blur a lot with Next.js but since the server-action is called from the frontend, that bit of code should only be concerned with pure data and not a specific "representation" the ORM then deals with it. You can still convert it to a Prisma.Decimal before storing it in the database.