Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fetch request body as application/x-www-form-urlencoded #633

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

Closed
duchoang opened this issue Nov 16, 2021 · 9 comments
Closed

Fetch request body as application/x-www-form-urlencoded #633

duchoang opened this issue Nov 16, 2021 · 9 comments
Labels

Comments

@duchoang
Copy link

While upgrading ScalaJS from 1.x to 2.x, we are hitting to this issue with sending data with urlencoded type (in version 1.x we were using Ajax, now we must switch to fetch())

Example with this simple code:

import org.scalajs.dom._

val headers = new Headers()
headers.set("content-type", "application/x-www-form-urlencoded")
Fetch
      .fetch(
        "/test-api",
        new RequestInit {
          method = HttpMethod.POST
          body = "key1=value1&key2=value2"
          headers = headers
        }
      )

When executing this script in browser, the content-type header of fetch request is changed to be text/plain;charset=UTF-8. It seems ScalaJs itselves detects the body as string and decide to change the content-type to text/plain which is wrong.

If I use the same code above directly with javascript here (testing by openning the chrome console), the fetch request is sent correctly with content-type urlencoded.

window.fetch('/test-api', {
  method: 'POST',
  headers: {
  	'content-type': 'application/x-www-form-urlencoded'
  },
  body: 'key1=value1&key2=value2'
})

Could you please show me how to use this properly?

While I search some solution for this, I notice one workaround for this is to use this type URLSearchParams in the body of fetch request, this will set the content-type automatically to urlencoded. But sadly the type of request body RequestInit doesnt support this yet:

Blob | BufferSource | FormData | String // todo: add URLSearchParams

@armanbilge
Copy link
Member

armanbilge commented Nov 16, 2021

Thanks for reporting. That is indeed strange, I can't understand why scala-js-dom would do something different than vanilla JavaScript: it is purely a facade for the JavaScript API.

What browser are you testing with?

Can you try setting the headers in Scala.js like this:

Fetch
      .fetch(
        "/test-api",
        new RequestInit {
          method = HttpMethod.POST
          body = "key1=value1&key2=value2"
          headers = js.Dictionary("content-type" -> "application/x-www-form-urlencoded")
        }
      )

This matches your JavaScript code more closely.

Similarly, can you try changing the JavaScript code to:

var headers = new Headers();
headers.set("content-type", "application/x-www-form-urlencoded");
window.fetch('/test-api', {
  method: 'POST',
  headers: headers,
  body: 'key1=value1&key2=value2'
})

This matches the original Scala.js code that has the problem.

Please try those and let me know what happens.


Regarding URLSearchParams...

But sadly the type of request body RequestInit doesnt support this yet:

It seems we have a facade for URLSearchParams already, it just needs to be added to the union there. Would you like to make a PR? :)

class URLSearchParams extends js.Iterable[js.Tuple2[String, String]] {

@duchoang
Copy link
Author

Thanks @armanbilge for your detail reply, to make it easier testing, I setup a new project to demonstrate this issue here:

https://github.com/duchoang/scalajs-fetch-urlencoded/blob/main/client/src/main/scala/example/client.scala#L11

Button1 is using Headers type and button2 is using js.Dictionary type.

To run this example, you can run these sbt command:

$> sbt
sbt:scalajs-fetch-urlencoded> compile
sbt:scalajs-fetch-urlencoded> webserver/run

Open example web at http://localhost:8080/ and click the first button, the fetch request is sent with header content-type: text/plain

image

while for second button, it is sent correctly with form-urlencoded

image

Thanks for the suggestion with js.Dictionary, it works for our case, but why it is failing with Headers type is still a mystery, I leave this to your side to investigate more, feel free to check out the above example code and test.

In addition, I'm happy to raise a PR to let BodyInit type support this URLSearchParams, will do it soon.

@armanbilge
Copy link
Member

Thank you for setting up the example! Very helpful. Look forward to the PR :)

Glad you have a working solution for now, we'll investigate the problem with Headers.

@armanbilge armanbilge added this to the v2.1.0 milestone Nov 16, 2021
@armanbilge
Copy link
Member

armanbilge commented Nov 16, 2021

Ah, this is quite silly actually! This code will work.

val myHeaders = new Headers()
myHeaders.set("content-type", "application/x-www-form-urlencoded")
Fetch
      .fetch(
        "/test-api",
        new RequestInit {
          method = HttpMethod.POST
          body = "key1=value1&key2=value2"
          headers = myHeaders
        }
      )

headers was cyclically referencing itself, not the variable defined above.

@armanbilge armanbilge removed this from the v2.1.0 milestone Nov 16, 2021
@yurique
Copy link

yurique commented Nov 16, 2021

Oh wow, I would never have guessed! :)

@yurique
Copy link

yurique commented Nov 16, 2021

BTW, I think I did a similar thing for a different trait, but one of the scalac warnings got triggered (something like "this thing is doing nothing except referencing itself", might have been scala3)

@armanbilge
Copy link
Member

Yes, I think also enabling warnings about unused variables (which Scala 2 has) would help catch thisβ€”not the cyclic reference of course, but the unused Headers above :)

-Xlint:unused
    Enable -Wunused:imports,privates,locals,implicits.

@duchoang
Copy link
Author

@armanbilge wow thanks for your debugging, didn't notice that self-referencing πŸ˜‚

@armanbilge
Copy link
Member

@duchoang btw I noticed you are using http4s in your example project, you may find this project useful: https://github.com/http4s/http4s-dom

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants