Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/content/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
],
},
Expand Down
96 changes: 96 additions & 0 deletions apps/content/docs/helpers/form-data.md
Original file line number Diff line number Diff line change
@@ -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'
Comment thread
dinwwwh marked this conversation as resolved.

export function ContactForm() {
const [error, setError] = useState()

const handleSubmit = (form: FormData) => {
try {
const data = parseFormData(form)
// Process structured data
}
catch (error) {
setError(error)
}
}

return (
<form action={handleSubmit}>
Comment thread
dinwwwh marked this conversation as resolved.
<input name="user[name]" type="text" />
<span>{getIssueMessage(error, 'user[name]')}</span>

<input name="user[emails][]" type="email" />
<span>{getIssueMessage(error, 'user[emails][]')}</span>

<button type="submit">Submit</button>
</form>
)
}
```
11 changes: 0 additions & 11 deletions apps/content/docs/openapi/bracket-notation.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,4 @@ This form data is parsed as:
"files": ["<binary data>", "<binary data>"]
}
}
```

"files": ["<binary data>", "<binary data>"]

}
}
}
}

```

```
9 changes: 2 additions & 7 deletions apps/content/docs/server-action.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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.
:::
6 changes: 6 additions & 0 deletions packages/openapi-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/openapi-client/src/helpers/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
it('exports something', async () => {
expect(await import('./index')).toHaveProperty('getIssueMessage')
})
1 change: 1 addition & 0 deletions packages/openapi-client/src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getIssueMessage, parseFormData } from '../adapters/standard'
Loading