Skip to content

Commit 4b3a4c5

Browse files
authored
feat(openapi): form-data helpers (#951)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Exposed Form Data helpers in the OpenAPI client to parse nested form submissions and retrieve validation messages via bracket notation. * **Documentation** * Added a “Form Data” guide with usage examples and a sidebar link. * Streamlined server-action docs to reference the re-exported helpers. * Fixed formatting in the bracket-notation complex example. * **Tests** * Added a test to verify the helpers entry is available. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent f437dcb commit 4b3a4c5

File tree

7 files changed

+109
-18
lines changed

7 files changed

+109
-18
lines changed

apps/content/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export default withMermaid(defineConfig({
154154
{ text: 'Base64Url', link: '/docs/helpers/base64url' },
155155
{ text: 'Cookie', link: '/docs/helpers/cookie' },
156156
{ text: 'Encryption', link: '/docs/helpers/encryption' },
157+
{ text: 'Form Data', link: '/docs/helpers/form-data' },
157158
{ text: 'Signing', link: '/docs/helpers/signing' },
158159
],
159160
},
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
title: Form Data Helpers
3+
description: Utilities for parsing form data and handling validation errors with bracket notation support.
4+
---
5+
6+
# Form Data Helpers
7+
8+
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.
9+
10+
## `parseFormData`
11+
12+
Parses HTML form data using [bracket notation](/docs/openapi/bracket-notation) to deserialize complex nested objects and arrays.
13+
14+
```ts twoslash
15+
import { parseFormData } from '@orpc/openapi-client/helpers'
16+
17+
const form = new FormData()
18+
form.append('name', 'John')
19+
form.append('user[email]', 'john@example.com')
20+
form.append('user[hobbies][]', 'reading')
21+
form.append('user[hobbies][]', 'gaming')
22+
23+
const parsed = parseFormData(form)
24+
// Result:
25+
// {
26+
// name: 'John',
27+
// user: {
28+
// email: 'john@example.com',
29+
// hobbies: ['reading', 'gaming']
30+
// }
31+
// }
32+
```
33+
34+
## `getIssueMessage`
35+
36+
Extracts validation error messages from [standard schema](https://github.com/standard-schema/standard-schema) issues using [bracket notation](/docs/openapi/bracket-notation) paths.
37+
38+
```ts twoslash
39+
import { getIssueMessage } from '@orpc/openapi-client/helpers'
40+
41+
const error = {
42+
data: {
43+
issues: [
44+
{
45+
path: ['user', 'email'],
46+
message: 'Invalid email format'
47+
}
48+
]
49+
}
50+
}
51+
52+
const emailError = getIssueMessage(error, 'user[email]')
53+
// Returns: 'Invalid email format'
54+
55+
const tagError = getIssueMessage(error, 'user[tags][]')
56+
// Returns error message for any array item
57+
58+
const anyError = getIssueMessage('anything', 'path')
59+
// Returns undefined if cannot find issue
60+
```
61+
62+
::: warning
63+
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.
64+
:::
65+
66+
## Usage Example
67+
68+
```tsx
69+
import { getIssueMessage, parseFormData } from '@orpc/openapi-client/helpers'
70+
71+
export function ContactForm() {
72+
const [error, setError] = useState()
73+
74+
const handleSubmit = (form: FormData) => {
75+
try {
76+
const data = parseFormData(form)
77+
// Process structured data
78+
}
79+
catch (error) {
80+
setError(error)
81+
}
82+
}
83+
84+
return (
85+
<form action={handleSubmit}>
86+
<input name="user[name]" type="text" />
87+
<span>{getIssueMessage(error, 'user[name]')}</span>
88+
89+
<input name="user[emails][]" type="email" />
90+
<span>{getIssueMessage(error, 'user[emails][]')}</span>
91+
92+
<button type="submit">Submit</button>
93+
</form>
94+
)
95+
}
96+
```

apps/content/docs/openapi/bracket-notation.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,4 @@ This form data is parsed as:
107107
"files": ["<binary data>", "<binary data>"]
108108
}
109109
}
110-
```
111-
112-
"files": ["<binary data>", "<binary data>"]
113-
114-
}
115-
}
116-
}
117-
}
118-
119-
```
120-
121110
```

apps/content/docs/server-action.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,9 @@ By moving the `redirect('/some-where')` logic into `createFormAction` rather tha
273273
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).
274274
:::
275275

276-
### `parseFormData` and `getIssueMessage` utilities
276+
### Form Data Utilities
277277

278-
- `parseFormData` parse a form data with [Bracket Notation](/docs/openapi/bracket-notation)
279-
- `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
278+
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.
280279

281280
```tsx
282281
import { getIssueMessage, parseFormData } from '@orpc/react'
@@ -311,7 +310,3 @@ export function MyComponent() {
311310
)
312311
}
313312
```
314-
315-
::: info
316-
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.
317-
:::

packages/openapi-client/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
"import": "./dist/index.mjs",
2121
"default": "./dist/index.mjs"
2222
},
23+
"./helpers": {
24+
"types": "./dist/helpers/index.d.mts",
25+
"import": "./dist/helpers/index.mjs",
26+
"default": "./dist/helpers/index.mjs"
27+
},
2328
"./standard": {
2429
"types": "./dist/adapters/standard/index.d.mts",
2530
"import": "./dist/adapters/standard/index.mjs",
@@ -34,6 +39,7 @@
3439
},
3540
"exports": {
3641
".": "./src/index.ts",
42+
"./helpers": "./src/helpers/index.ts",
3743
"./standard": "./src/adapters/standard/index.ts",
3844
"./fetch": "./src/adapters/fetch/index.ts"
3945
},
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
it('exports something', async () => {
2+
expect(await import('./index')).toHaveProperty('getIssueMessage')
3+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { getIssueMessage, parseFormData } from '../adapters/standard'

0 commit comments

Comments
 (0)