-
-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support passing schema via async function (#154)
The code in this PR adds the support for passing a schema to the action via an async function inside the `schema` method. This is necessary, for instance, when you're using a i18n solution that requires to await the translations and pass them to schemas, as discussed in #111.
- Loading branch information
Showing
13 changed files
with
163 additions
and
26 deletions.
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
apps/playground/src/app/(examples)/async-schema/login-action.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
"use server"; | ||
|
||
import { action } from "@/lib/safe-action"; | ||
import { | ||
flattenValidationErrors, | ||
returnValidationErrors, | ||
} from "next-safe-action"; | ||
import { z } from "zod"; | ||
|
||
async function getSchema() { | ||
return z.object({ | ||
username: z.string().min(3).max(10), | ||
password: z.string().min(8).max(100), | ||
}); | ||
} | ||
|
||
export const loginUser = action | ||
.metadata({ actionName: "loginUser" }) | ||
.schema(getSchema, { | ||
// Here we use the `flattenValidationErrors` function to customize the returned validation errors | ||
// object to the client. | ||
handleValidationErrorsShape: (ve) => | ||
flattenValidationErrors(ve).fieldErrors, | ||
}) | ||
.action(async ({ parsedInput: { username, password } }) => { | ||
if (username === "johndoe") { | ||
returnValidationErrors(getSchema, { | ||
username: { | ||
_errors: ["user_suspended"], | ||
}, | ||
}); | ||
} | ||
|
||
if (username === "user" && password === "password") { | ||
return { | ||
success: true, | ||
}; | ||
} | ||
|
||
returnValidationErrors(getSchema, { | ||
username: { | ||
_errors: ["incorrect_credentials"], | ||
}, | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
"use client"; | ||
|
||
import { StyledButton } from "@/app/_components/styled-button"; | ||
import { StyledHeading } from "@/app/_components/styled-heading"; | ||
import { StyledInput } from "@/app/_components/styled-input"; | ||
import { useState } from "react"; | ||
import { ResultBox } from "../../_components/result-box"; | ||
import { loginUser } from "./login-action"; | ||
|
||
export default function DirectExamplePage() { | ||
const [result, setResult] = useState<any>(undefined); | ||
|
||
return ( | ||
<main className="w-96 max-w-full px-4"> | ||
<StyledHeading> | ||
Action using direct call | ||
<br /> | ||
(async schema) | ||
</StyledHeading> | ||
<form | ||
className="flex flex-col mt-8 space-y-4" | ||
onSubmit={async (e) => { | ||
e.preventDefault(); | ||
const formData = new FormData(e.currentTarget); | ||
const input = Object.fromEntries(formData) as { | ||
username: string; | ||
password: string; | ||
}; | ||
const res = await loginUser(input); // this is the typesafe action directly called | ||
setResult(res); | ||
}}> | ||
<StyledInput | ||
type="text" | ||
name="username" | ||
id="username" | ||
placeholder="Username" | ||
/> | ||
<StyledInput | ||
type="password" | ||
name="password" | ||
id="password" | ||
placeholder="Password" | ||
/> | ||
<StyledButton type="submit">Log in</StyledButton> | ||
</form> | ||
<ResultBox result={result} /> | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
--- | ||
sidebar_position: 5 | ||
description: Learn how to use next-safe-action with a i18n solution. | ||
--- | ||
|
||
# i18n | ||
|
||
If you're using a i18n solution, there's a high probability that you'll need to await the translations and then pass them to schemas.\ | ||
next-safe-action allows you to do that by passing an async function to the [`schema`](/docs/safe-action-client/instance-methods#schema) method that returns a promise with the schema.\ | ||
The setup is pretty simple: | ||
|
||
```typescript | ||
"use server"; | ||
|
||
import { actionClient } from "@/lib/safe-action"; | ||
import { z } from "zod"; | ||
import { getTranslations } from "my-i18n-lib"; | ||
|
||
async function getSchema() { | ||
// This is an example of a i18n setup. | ||
const t = await getTranslations(); | ||
return mySchema(t); // this is the schema that will be used to validate and parse the input | ||
} | ||
|
||
export const myAction = actionClient.schema(getSchema).action(async ({ parsedInput }) => { | ||
// Do something useful here... | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters