-
-
Notifications
You must be signed in to change notification settings - Fork 624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(utils/body): add dot notation support for parseBody
#2675
Conversation
parseBody
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are some basic changes you can do to improve this. I haven't looked at the setNestedValue
func and the test cases (this was all the time I had 😅), but I will try to look at it soon.
@MathurAditya724 Reviews resolved, to decide whether is it |
Dot notation support documentation will be added here: https://hono.dev/api/request#parsebody Dot Notation// assume you pass `obj.key1` in the request body
const body = await c.req.parseBody({ UNDECIDED: true })
body['obj'] // { key1: 'value' }
All fields key with dot notation (e.g |
Yes, you will have to create a separate PR for that at https://github.com/honojs/website |
Woooow. Super fast and quick! I'll review this now. |
parseBody
parseBody
Thanks @yusukebe I will run denoify and lint once again |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some minor changes for the improvements you did based on my review
Hey. The following test does not pass now. But is this expected? What do you think? @fzn0x @MathurAditya724 it('should parse data if both `all` and `dot` are set', async () => {
const data = new FormData()
data.append('obj.sub.foo', 'value1')
data.append('obj.sub.foo', 'value2')
data.append('key', 'value3')
const req = createRequest(FORM_URL, 'POST', data)
expect(await parseBody(req, { dot: true, all: true })).toEqual({
obj: { sub: { foo: ['value1', 'value2'] } }, // Is tis expected??
key: 'value3',
})
}) Test test result:
|
This is unexpected, let me fix that @yusukebe |
Anyway, this is a new "feature," so it may not be merged into the main immediately. So you don't have to hurry up:) |
I need it for everyday tasks :) |
@fzn0x I believe |
Looks like if (
!nestedForm[key] ||
typeof nestedForm[key] !== 'object' ||
Array.isArray(nestedForm[key])
) {
nestedForm[key] = nestedForm[key] || {}
} This code only return the last value of the array @MathurAditya724 I will try to fix it and hope get back with good news |
Interesting, let me check |
Can I make changes to this PR? Or should I fork your repo? |
I found the solution but the hard thing is to keep the code clean 😅 @MathurAditya724 @yusukebe I guess we can continue with the review 🔥 |
I believe we can add this in |
Yes. Let's include this in |
Hi @fzn0x!
|
Fix added! kindly review, thanks @usualoma |
Sorry to add one more point. From a security standpoint, I think it would be better to prevent the File object's properties from being able to be updated. diff --git a/src/utils/body.test.ts b/src/utils/body.test.ts
index 41235292..fb6da697 100644
--- a/src/utils/body.test.ts
+++ b/src/utils/body.test.ts
@@ -191,6 +191,32 @@ describe('Parse Body Util', () => {
})
})
+ it('should not update file object properties', async () => {
+ const file = new File(['foo'], 'file1', {
+ type: 'application/octet-stream',
+ })
+ const data = new FormData()
+
+ const req = createRequest(FORM_URL, 'POST', data)
+ vi.spyOn(req, 'formData').mockImplementation(
+ async () =>
+ ({
+ forEach: (cb) => {
+ cb(file, 'file', data)
+ cb('hoo', 'file.hoo', data)
+ },
+ } as FormData)
+ )
+
+ const parsedData = await parseBody(req, { dot: true })
+ expect(parsedData.file).not.instanceOf(File)
+ expect(parsedData).toEqual({
+ file: {
+ hoo: 'hoo',
+ },
+ })
+ })
+
it('should parse multiple values if key ends with `[]`', async () => {
const data = new FormData()
data.append('file[]', 'aaa')
diff --git a/src/utils/body.ts b/src/utils/body.ts
index 1c77ab98..f07c6433 100644
--- a/src/utils/body.ts
+++ b/src/utils/body.ts
@@ -138,7 +138,8 @@ const handleNestedValues = (
if (
!nestedForm[key] ||
typeof nestedForm[key] !== 'object' ||
- Array.isArray(nestedForm[key])
+ Array.isArray(nestedForm[key]) ||
+ nestedForm[key] instanceof File
) {
nestedForm[key] = Object.create(null)
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @fzn0x, I have gone through the functions and made some improvements. All the tests are passing. Also, I added some pointers where we can improve this more. Let me know what you think
Thanks for the reviews, |
Adding tsdoc for better developer experience |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Thanks y'all. Now ready to merge to the |
Was about to implement this myself when I found this—awesome work! Curious—has there been any discussion around implementing the inverse (a flattenObject function) for the Hono client? It's relatively simple for the user to implement, but it would be nice to have a Hono-supported implementation that's guaranteed to be kept in sync (and losslessly round-trip) with this implementation. Would be awesome in terms of giving Hono even more of an RPC feel. |
Hi @iveshenry18 ! When we were challenged to create a function like a JSON path in our validator, we used a function similar to "flattenObject." But we decided not to make it. We will not implement it as a utility function if it does not require any features. |
Oops! I just checked and it was not a flattenObject, but a function that parses a dot-notation. |
Interesting—that's essentially what the code in this PR does. I'm suggesting a utility that can take a nested object and parse it into a flat object with dot-notation keys. That way you can have a nested object on the client side, parse it into a flat object, send it as multipart/form-data, then use Either way, I totally understand if that's out of scope for Hono! Just thought it might be a nice companion to this functionality. It seems like anyone using |
Closes #2656
cc @yusukebe @MathurAditya724
The author should do the following, if applicable
bun denoify
to generate files for Denobun run format:fix && bun run lint:fix
to format the code