From 95c2c1a5f57ec0b3a80b93af6b73ea039e5987b8 Mon Sep 17 00:00:00 2001 From: unnoq Date: Sun, 31 Aug 2025 16:14:58 +0700 Subject: [PATCH 1/2] feat(openapi): form-data helpers --- apps/content/.vitepress/config.ts | 1 + apps/content/docs/helpers/form-data.md | 96 +++++++++++++++++++ apps/content/docs/openapi/bracket-notation.md | 11 --- apps/content/docs/server-action.md | 9 +- packages/openapi-client/package.json | 6 ++ packages/openapi-client/src/helpers/index.ts | 1 + 6 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 apps/content/docs/helpers/form-data.md create mode 100644 packages/openapi-client/src/helpers/index.ts diff --git a/apps/content/.vitepress/config.ts b/apps/content/.vitepress/config.ts index 806d6887d..2b2c333b5 100644 --- a/apps/content/.vitepress/config.ts +++ b/apps/content/.vitepress/config.ts @@ -154,6 +154,7 @@ export default withMermaid(defineConfig({ { text: 'Base64Url', link: '/docs/helpers/base64url' }, { text: 'Cookie', link: '/docs/helpers/cookie' }, { text: 'Encryption', link: '/docs/helpers/encryption' }, + { text: 'Form Data', link: '/docs/helpers/form-data' }, { text: 'Signing', link: '/docs/helpers/signing' }, ], }, diff --git a/apps/content/docs/helpers/form-data.md b/apps/content/docs/helpers/form-data.md new file mode 100644 index 000000000..7d2638126 --- /dev/null +++ b/apps/content/docs/helpers/form-data.md @@ -0,0 +1,96 @@ +--- +title: Form Data Helpers +description: Utilities for parsing form data and handling validation errors with bracket notation support. +--- + +# Form Data Helpers + +Form data helpers provide utilities for parsing HTML form data and extracting validation error messages, with full support for [bracket notation](/docs/openapi/bracket-notation) to handle complex nested structures. + +## `parseFormData` + +Parses HTML form data using [bracket notation](/docs/openapi/bracket-notation) to deserialize complex nested objects and arrays. + +```ts twoslash +import { parseFormData } from '@orpc/openapi-client/helpers' + +const form = new FormData() +form.append('name', 'John') +form.append('user[email]', 'john@example.com') +form.append('user[hobbies][]', 'reading') +form.append('user[hobbies][]', 'gaming') + +const parsed = parseFormData(form) +// Result: +// { +// name: 'John', +// user: { +// email: 'john@example.com', +// hobbies: ['reading', 'gaming'] +// } +// } +``` + +## `getIssueMessage` + +Extracts validation error messages from [standard schema](https://github.com/standard-schema/standard-schema) issues using [bracket notation](/docs/openapi/bracket-notation) paths. + +```ts twoslash +import { getIssueMessage } from '@orpc/openapi-client/helpers' + +const error = { + data: { + issues: [ + { + path: ['user', 'email'], + message: 'Invalid email format' + } + ] + } +} + +const emailError = getIssueMessage(error, 'user[email]') +// Returns: 'Invalid email format' + +const tagError = getIssueMessage(error, 'user[tags][]') +// Returns error message for any array item + +const anyError = getIssueMessage('anything', 'path') +// Returns undefined if cannot find issue +``` + +::: warning +The `getIssueMessage` utility works with any data type but requires validation errors to follow the [standard schema issue format](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#the-interface). It looks for issues in the `data.issues` property. If you use custom [validation errors](/docs/advanced/validation-errors), store them elsewhere, or modify the issue format, `getIssueMessage` may not work as expected. +::: + +## Usage Example + +```tsx +import { getIssueMessage, parseFormData } from '@orpc/openapi-client/helpers' + +export function ContactForm() { + const [error, setError] = useState() + + const handleSubmit = (form: FormData) => { + try { + const data = parseFormData(form) + // Process structured data + } + catch (error) { + setError(error) + } + } + + return ( +
+ + {getIssueMessage(error, 'user[name]')} + + + {getIssueMessage(error, 'user[emails][]')} + + +
+ ) +} +``` diff --git a/apps/content/docs/openapi/bracket-notation.md b/apps/content/docs/openapi/bracket-notation.md index 00bb99629..8d1e3d517 100644 --- a/apps/content/docs/openapi/bracket-notation.md +++ b/apps/content/docs/openapi/bracket-notation.md @@ -107,15 +107,4 @@ This form data is parsed as: "files": ["", ""] } } -``` - - "files": ["", ""] - -} -} -} -} - -``` - ``` diff --git a/apps/content/docs/server-action.md b/apps/content/docs/server-action.md index 7643c6a9c..3a26b0a41 100644 --- a/apps/content/docs/server-action.md +++ b/apps/content/docs/server-action.md @@ -273,10 +273,9 @@ By moving the `redirect('/some-where')` logic into `createFormAction` rather tha When using `createFormAction`, any `ORPCError` with a status of `401`, `403`, or `404` is automatically converted into the corresponding Next.js error responses: [unauthorized](https://nextjs.org/docs/app/api-reference/functions/unauthorized), [forbidden](https://nextjs.org/docs/app/api-reference/functions/forbidden), and [not found](https://nextjs.org/docs/app/api-reference/functions/not-found). ::: -### `parseFormData` and `getIssueMessage` utilities +### Form Data Utilities -- `parseFormData` parse a form data with [Bracket Notation](/docs/openapi/bracket-notation) -- `getIssueMessage` get the [standard schema](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#the-interface) issue message with [Bracket Notation](/docs/openapi/bracket-notation) path +The `@orpc/react` package re-exports [Form Data Helpers](/docs/helpers/form-data) for seamless form data parsing and validation error handling with [bracket notation](/docs/openapi/bracket-notation) support. ```tsx import { getIssueMessage, parseFormData } from '@orpc/react' @@ -311,7 +310,3 @@ export function MyComponent() { ) } ``` - -::: info -The `getIssueMessage` utility works with any data type but requires validation errors to follow the [standard schema issue format](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#the-interface). It looks for issues in the `data.issues` property. If you use custom [validation errors](/docs/advanced/validation-errors), store them elsewhere, or modify the issue format, `getIssueMessage` may not work as expected. -::: diff --git a/packages/openapi-client/package.json b/packages/openapi-client/package.json index 14e61afde..d9ba3bc0d 100644 --- a/packages/openapi-client/package.json +++ b/packages/openapi-client/package.json @@ -20,6 +20,11 @@ "import": "./dist/index.mjs", "default": "./dist/index.mjs" }, + "./helpers": { + "types": "./dist/helpers/index.d.mts", + "import": "./dist/helpers/index.mjs", + "default": "./dist/helpers/index.mjs" + }, "./standard": { "types": "./dist/adapters/standard/index.d.mts", "import": "./dist/adapters/standard/index.mjs", @@ -34,6 +39,7 @@ }, "exports": { ".": "./src/index.ts", + "./helpers": "./src/helpers/index.ts", "./standard": "./src/adapters/standard/index.ts", "./fetch": "./src/adapters/fetch/index.ts" }, diff --git a/packages/openapi-client/src/helpers/index.ts b/packages/openapi-client/src/helpers/index.ts new file mode 100644 index 000000000..7a15b46bd --- /dev/null +++ b/packages/openapi-client/src/helpers/index.ts @@ -0,0 +1 @@ +export { getIssueMessage, parseFormData } from '../adapters/standard' From c9e184c2eb8f5a4b1a3dde1890ccb814d9012c04 Mon Sep 17 00:00:00 2001 From: unnoq Date: Sun, 31 Aug 2025 16:20:00 +0700 Subject: [PATCH 2/2] tests --- packages/openapi-client/src/helpers/index.test.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 packages/openapi-client/src/helpers/index.test.ts diff --git a/packages/openapi-client/src/helpers/index.test.ts b/packages/openapi-client/src/helpers/index.test.ts new file mode 100644 index 000000000..764842156 --- /dev/null +++ b/packages/openapi-client/src/helpers/index.test.ts @@ -0,0 +1,3 @@ +it('exports something', async () => { + expect(await import('./index')).toHaveProperty('getIssueMessage') +})