softwaremill / sttp

The Scala HTTP client you always wanted!
https://sttp.softwaremill.com
Apache License 2.0
1.45k stars 309 forks source link

POST call with raw body #220

Open sonal1111 opened 5 years ago

sonal1111 commented 5 years ago

Can you provide an example about how can we make POST call with raw body in sttp. So far I have only dealt with form data. My raw body can be a JSON payload or a text on use case basis.

adamw commented 5 years ago

sttp.body("some data") should work fine. You can also provide a custom content type header value using sttp.bod("xyz").contentType("x/y")

sonal1111 commented 5 years ago

{ "resourceName":"d2_dev_lineage_rave_empty" }

I need to pass above json object in my body. Can you provide an example how it can be done

adamw commented 5 years ago
sttp.body("""
{
  "resourceName":"d2_dev_lineage_rave_empty"
}
""").contentType("application/json")
sonal1111 commented 5 years ago
 request = sttp
          .post(uri"https://sample-endpoint.com")
          .body("""{"resourceName":"d2_dev_lineage_rave_empty"}""")
          .contentType("application/json")
          .headers(headers)
          .auth.basic(auth.getOrElse("username", ""), auth.getOrElse("password", ""))

I tried above code but it gives 400 error code but strangely same endpoint works fine for me in Postman. What possibly could be the reason?

image

sonal1111 commented 5 years ago

One thing I noted is my request created has below StringBody. It has Some(text/plain) whereas in Postman it is configured as "application/json" . Could this be a reason for a Bad Request? StringBody({"resourceName":"d2_dev_lineage_rave_empty"},utf-8,Some(text/plain))

sonal1111 commented 5 years ago

Looks like there is some bug with sttp. I invoked same REST endpoint with HTTPClient and it worked for me.

adamw commented 5 years ago

What's in the headers value that you pass to headers?

Could you do a println(request) so that we can see all the final values that are produced there?

adamw commented 5 years ago

Closing due to lack of activity

manasbajaj commented 4 years ago

Hello @adamw -- I am facing the same issue. I am using version 2.2.8 of the sttp client API. When the request is sent via Postman, the curl command shows the body of the GET sent with --data-raw. However, when the request is sent via sttp using the approach you provided in the comment on 20-Jun above, the curl request shows --data instead of --data-raw. The receiving application which expects a raw body data with a GET rejects it.

adamw commented 4 years ago

@manasbajaj could you pmaybe provide a way to reproduce the problem locally?

manasbajaj commented 4 years ago

@adamw -- Thanks for opening this. I will provide more info shortly.

manasbajaj commented 4 years ago

Hello @adamw

I am working with an application and one of the endpoints in their REST API requires me to pass the following raw JSON in the body of a GET request.

{"item_number":"SYN01-Part-A"}

Here is the print of the Request object that gets created using sttp client. As you can see a StringBody is used to represent the JSON body above. I have replaced the bearer token with the placeholder to focus on the main part of the request.

RequestT(GET,https://someServer.com/odata/Part?$filter=generation+gt+0,StringBody({"item_number":"SYN01-Part-A"},utf-8,Some(application/json)),Vector(Accept-Encoding: gzip, deflate, Content-Length: 30, Content-Type: application/json, Accept: application/json, Authorization: Bearer <Token> ),MappedResponseAs(ResponseAsByteArray,sttp.client.MappedResponseAs$$Lambda$230/33533830@62e6b5c8),RequestOptions(true,1 minute,32,false),Map())

Here is the print of request.toCurl method

curl -L --max-redirs 32 -X GET -H 'Content-Length: 30' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer <Token>' --data '{"item_number":"SYN01-Part-A"}' 'https://someServer.com/odata/Part?$filter=generation+gt+0'

The application rejects the above request.

However, the same request goes through when done via Postman. Here is the CURL request from Postman. The main difference you will notice is the --data-raw option below versus the --data option above. The request below gives a successful response.

curl --location --request GET 'https://someServer.com/odata/Part?$filter=generation%20gt%200' \ --header 'Authorization: Bearer <Token>' \ --header 'Content-Type: application/json' \ --data-raw '{"item_number": "SYN01-Part-A"}

wangxia337 commented 3 years ago

We have same problem!!!

kubinio123 commented 3 years ago

@manasbajaj @wangxia337 I tried to reproduce your issue.

I launched a simple app exposing POST endpoint which accepts body: {"name": "foo"}. Then I sent a request using HttpClientFutureBackend as well as using command line with generated curl:

curl -L --max-redirs 32 -X POST -H 'Content-Length: 15' -H 'Content-Type: application/json' --data '{"name": "foo"}' 'http://localhost:8080/post'.

Both calls didn't caused any errors and request body was consumed by application. Tested using v 2.2.8 and current master.

Please provide a way to reproduce the problem locally.

manasbajaj commented 3 years ago

Hello @kubinio123 - The curl request generated by Postman worked for us but not the one generated by the sttp library. Please see both below, as also stated in my previous comment. The application provided by another provider rejects the request generated by sttp library but accepts (and works fine) with the request generated by Postman, i.e. we get the expected response.

The main differences are: (1) --data (sttp) vs --data-raw (Postman) argument (2) Accept: application/json header (sttp) vs no such argument from Postman

Request generated by Postman curl --location --request GET 'https://someServer.com/odata/Part?$filter=generation%20gt%200' \ --header 'Authorization: Bearer <Token>' \ --header 'Content-Type: application/json' \ --data-raw '{"item_number": "SYN01-Part-A"}

Request generated using sttp library curl -L --max-redirs 32 -X GET -H 'Content-Length: 30' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer <Token>' --data '{"item_number":"SYN01-Part-A"}' 'https://someServer.com/odata/Part?$filter=generation+gt+0'

For your reference, here is the sttp call we are making that results in the request above: val request = basicRequest.auth.bearer(bearerToken).get(uri"$serverBaseUrl/server/odata/Part?$$filter=generation gt 0").body(s"""{"item_number":"SYN01-Part-A"}""").contentType("application/json")

ghostbuster91 commented 3 years ago

The body in both cases (--data and --data-raw) looks the same. Isn't that just a fault of additional Accept: application/json header?