vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.01k stars 26.99k forks source link

URLSearchParams does not survive serialization/deserialization when passed from a client to a Server Action #71078

Open Scrumplex opened 1 month ago

Scrumplex commented 1 month ago

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/exciting-meitner-zrdlrs

To Reproduce

  1. Write a Server Action that takes URLSearchParams
  2. Try to call it from a client component

Current vs. Expected behavior

When calling URLSearchParams#toString() in a Server Action, it yields a malformed output (foo,bar,next,js), instead of actual query/search params (foo=bar&next=js).

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
  Available memory (MB): 4102
  Available CPU cores: 2
Binaries:
  Node: 20.9.0
  npm: 9.8.1
  Yarn: 1.22.19
  pnpm: 8.10.2
Relevant Packages:
  next: 15.0.0-canary.182 // Latest available version is detected (15.0.0-canary.182).
  eslint-config-next: N/A
  react: 19.0.0-rc-2d16326d-20240930
  react-dom: 19.0.0-rc-2d16326d-20240930
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Not sure

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local)

Additional context

No response

Scrumplex commented 1 month ago

It seems like it gets serialized into a two-dimensional array.

I.e. URLSearchParams { 'foo' => 'bar' } -> [ [ 'foo', 'bar' ] ]

Bader975 commented 1 month ago

https://nextjs.org/docs/app/api-reference/functions/use-search-params i think you can configure it yourself $={search} and so on you find more example in docs @Scrumplex

Scrumplex commented 1 month ago

nextjs.org/docs/app/api-reference/functions/use-search-params i think you can configure it yourself $={search} and so on you find more example in docs @Scrumplex

I don't want to find out the current search params, but rather construct my own search params that I can then send off to an external API. The server action from my reproduction example just returns the string, but in my application the query params would be sent off to an API.

For example, I have a client component that provides auto-completion using a search endpoint of my external API and in order to call the API I would just call a Server Action using await searchThing(params/* : URLSearchParams /*) but doing so results in a malformed query string on the server action.

Bader975 commented 1 month ago

nextjs.org/docs/app/api-reference/functions/use-search-params i think you can configure it yourself $={search} and so on you find more example in docs @Scrumplex

I don't want to find out the current search params, but rather construct my own search params that I can then send off to an external API. The server action from my reproduction example just returns the string, but in my application the query params would be sent off to an API.

For example, I have a client component that provides auto-completion using a search endpoint of my external API and in order to call the API I would just call a Server Action using await searchThing(params/* : URLSearchParams /*) but doing so results in a malformed query string on the server action.

so this what i come up with : the codesandbox URL https://codesandbox.io/p/devbox/exciting-meitner-zrdlrs?file=%2Fapp%2FSearchParamsButton.tsx%3A14%2C28

'use server';

export const showSearchParams = async(stringifiedParams) => {
// Parse the stringified query back to URLSearchParams
    const params = new URLSearchParams(stringifiedParams);    
    return params.toString()
}

This will give you 'foo=bar&next=js' try it out and tell me what you got !!! 💯

image
Scrumplex commented 1 month ago

But at that point, I could just use the string directly in my target URL.

'use server';

export const showSearchParams = async(stringifiedParams: string) => {
    return stringifiedParams;
}

I wanted to use URLSearchParams as it allows me to send parameters in a structured way. Perhaps I could also pass them as an object/Record<string, string> but I would like to avoid extra steps like this.

Usually, Next.js will throw an error if something can't be serialized properly, so I think Next.js should either throw a warning when passing URLSearchParams, or fix the serialization.

Bader975 commented 1 month ago

But at that point, I could just use the string directly in my target URL.


'use server';

export const showSearchParams = async(stringifiedParams: string) => {

    return stringifiedParams;

}

I wanted to use URLSearchParams as it allows me to send parameters in a structured way. Perhaps I could also pass them as an object/Record<string, string> but I would like to avoid extra steps like this.

Usually, Next.js will throw an error if something can't be serialized properly, so I think Next.js should either throw a warning when passing URLSearchParams, or fix the serialization.

you are right 👍🏻 ,