With using org.http4s.client can't find how I can send headers and UriForm together with Post request.
import org.http4s.client.dsl.io._
import org.http4s.Method._
val lstHeader: List[Header] = List(
Header("Accept", "application/json")
, Header("Accept-Charset", "utf-8")
, Header("Accept-Encoding", "gzip")
)
val formData :UrlForm = UrlForm(
"username" -> "user",
"enc_password" -> "password",
"queryParams" -> "{}",
"optIntoOneTap" -> "false"
)
val req1 = POST(
formData,
uri"https://www.instagram.com/accounts/login/ajax/"
)
val req2: Request[IO] = Request[IO](
Method.POST,
uri"https://www.instagram.com/accounts/login/ajax/",
HttpVersion.`HTTP/2.0`,
Headers(lstHeader)
)
req1 without my headers
req2 without form data
Thanks
I found
val req2: Request[IO] = Request[IO](
Method.POST,
uri"https://www.instagram.com/accounts/login/ajax/",
HttpVersion.`HTTP/2.0`,
Headers(lstHeader)
).withEntity(formData)
Related
I have the following code that makes a simple POST request. How it should work? Before I have made a request, I generate a testing value "orderName1" and save it to the session. Next, I am using the function "create" to make the request and using the generated value in a function. And it works fine! My request is successful. As result, I have an order with a dynamically generated name "Name_68hKl90G". But I want to save the id, returned from the server into the session. I want to use "Name_68hKl90G" as a key into the session.
How it should work (session):
orderName1 -> Name_68hKl90G
Name_68hKl90G -> 63d80b25cb6c2a7e7e845e40
How it actually work (session):
orderName1 -> Name_68hKl90G
${orderName1} -> 63d80b25cb6c2a7e7e845e40
Code:
val generateStr = (symbols: Integer) => Random.alphanumeric.take(symbols).mkString
val prepareData = exec(
session => {
val newSession = session
.set("orderName1", "Name_" + generateStr(8))
newSession
}
)
def create(name: String) = exec(
http("Create order")
.post("/shop/order")
.body(StringBody(s"""{"name":"${name}"}""".stripMargin)).asJson
.check(status.is(201))
.check(jsonPath("$.id").saveAs(s"${name}"))
)
val userScn = scenario("Scenario")
.exec(
prepareData,
create("${orderName1}")
)
setUp(
userScn.inject(rampUsers(rampUpUserCount) during (rampUpDuration seconds)),
).protocols(httpProtocol)
def create(name: String) =
exec(
http("Create order")
.post("/shop/order")
.body(StringBody(s"""{"name":"#{$name}"}""")).asJson
.check(status.is(201))
.check(jsonPath("$.id").saveAs("id"))
).exec { session =>
val nameValue = session(name).as[String]
val id = session("id").as[String]
session.remove("id").set(nameValue, id)
}
create("orderName1")
Honestly, this looks overly complicated. I don't get why you don't want to use 2 different attributes, one for the key and one for the value.
It is no need to use session value as a key for other value.
You can satisfy all needs by following code:
val generateStr = (symbols: Integer) => Random.alphanumeric.take(symbols).mkString
val prepareData = exec(
session => {
val newSession = session
.set("orderName1", "Name_" + generateStr(8))
newSession
}
)
def create(name: String) = exec(
http("Create order")
.post("/shop/order")
.body(StringBody(session => s"""{"name":"${session(name).as[String]}"}""".stripMargin)).asJson
.check(status.is(201))
.check(jsonPath("$.id").saveAs(s"${name}_id"))
)
def rename(name: String, newName: String) = exec(
http("Update order name")
.patch(session => s"/shop/order/${session(name + "_id").as[String]}")
.body(StringBody(session => s"""{"name":"${newName}"}""".stripMargin)).asJson
.check(status.is(200))
)
val userScn = scenario("Scenario")
.exec(
prepareData,
create("orderName1"),
rename("orderName1", "New name")
)
setUp(
userScn.inject(rampUsers(rampUpUserCount) during (rampUpDuration seconds)),
).protocols(httpProtocol)
I want to send a file to Stripe using Play! Scala 2.5.
The documentation says that the request should be (curl equivalent) like this:
curl https://uploads.stripe.com/v1/files \
-u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
-F purpose=dispute_evidence \
-F file="#/path/to/a/file.jpg"
Mine is:
def test: Action[MultipartFormData[TemporaryFile]] = Action(parse.multipartFormData) { request =>
val image = request.body.file("picture").get
val info = Map("purpose" -> Seq("identity_document"))
val attachment =
FilePart[TemporaryFile](
key = "file",
filename = "file",
contentType = image.contentType,
ref = image.ref)
val formData: MultipartFormData[TemporaryFile] =
MultipartFormData(
dataParts = info,
files = Seq(attachment),
badParts = Seq.empty)
import services.MultipartFormDataWritable.anyContentAsMultipartFormWritable
wSClient
.url("https://uploads.stripe.com/v1/files")
.withAuth("secret_key", "", WSAuthScheme.BASIC)
.post(formData)
.map(response => println(response.body))
Ok
}
But Stripe returns me this Bad Request error:
"error": {
"type": "invalid_request_error",
"message": "Missing required param: file.",
"param": "file"
}
What am I doing wrong?
This works:
val file = request.body.file("picture").get
val filename = file.filename
val contentType = file.contentType.getOrElse(logAndThrowException("Id card without content type"))
if (contentType != "image/png" && contentType != "image/jpeg" && contentType != "image/jpg") {
logAndThrowException("Wrong content type (jp[e]g or png required)")
}
val tmpFile = file.ref.file
wSClient
.url("https://uploads.stripe.com/v1/files")
.withAuth(stripeTestAPIKey, "", WSAuthScheme.BASIC)
.withHeaders("Stripe-Account" -> stripeAccount)
.post(
Source(
iterable =
FilePart("file", filename, Option("text/plain"),
FileIO.fromPath(tmpFile.toPath)) ::
DataPart("purpose", "identity_document") ::
List()))
I have parsed json response and saved it using .findAll(). What I want to do is, ignore keyframeId if value is '-1' else put keyframeId in .get() request with loop. I did some code but the value doesnt set in get() request and gives 'KO'. Here it takes all the values in Vector and place all in single http call see error for details. Also I am not sure about the doIf condition. Can you please help? Thanks.
My Json response format is like this.
{
totalCount: 1134,
limit: 9,
offset: 0,
resources: [
{
title: "Test",
keyframeId: -1
}
{
title: "Test1",
keyframeId: 12345
}
{
title: "Test2",
keyframeId: 12341
}
{
title: "Test3",
keyframeId: -1
}
{
title: "Test4",
keyframeId: 135481
}
....
....
]}
Here is the gatling script,
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
class MamamSearch extends Simulation {
val testServerUrl = System.getProperty("testServerUrl", "https://someurl")
val username = System.getProperty("username", "ma")
val password = System.getProperty("password", "ma")
val userCount = Integer.getInteger("userCount", 1).toInt
val httpProtocol = http
.baseURL(testServerUrl)
.inferHtmlResources(BlackList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.(t|o)tf""", """.*\.png"""), WhiteList())
val headers_0 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Cache-Control" -> "max-age=0",
"Upgrade-Insecure-Requests" -> "1")
val headers_2 = Map("Accept" -> "text/css,*/*;q=0.1")
val headers_6 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding" -> "gzip, deflate, br",
"Cache-Control" -> "max-age=0",
"Origin" -> testServerUrl,
"Upgrade-Insecure-Requests" -> "1")
val headers_80 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Upgrade-Insecure-Requests" -> "1")
val headers_7 = Map("Accept" -> "image/webp,image/*,*/*;q=0.8")
val headers_11 = Map("Origin" -> testServerUrl)
val headers_12 = Map(
"Cache-Control" -> "no-cache",
"If-Modified-Since" -> "Mon, 26 Jul 1997 05:00:00 GMT",
"Pragma" -> "no-cache",
"X-Requested-With" -> "XMLHttpRequest")
val headers_15 = Map(
"Accept" -> "application/json, text/plain, */*",
"Cache-Control" -> "no-cache",
"If-Modified-Since" -> "Mon, 26 Jul 1997 05:00:00 GMT",
"Pragma" -> "no-cache",
"X-Requested-With" -> "XMLHttpRequest")
val headers_16 = Map("Accept" -> "*/*")
val headers_18 = Map(
"Accept" -> "text/html",
"Cache-Control" -> "no-cache",
"If-Modified-Since" -> "Mon, 26 Jul 1997 05:00:00 GMT",
"Pragma" -> "no-cache",
"X-Requested-With" -> "XMLHttpRequest")
val headers_19 = Map(
"Accept" -> "*/*",
"Accept-Encoding" -> "gzip, deflate, br",
"Origin" -> testServerUrl)
val headers_27 = Map(
"Accept" -> "*/*",
"Accept-Encoding" -> "gzip, deflate, br",
"Content-type" -> "text/plain",
"Origin" -> testServerUrl)
val uri1 = testServerUrl + "/mamam"
val uri2 = "https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0"
// Login request
val scn = scenario("MamamSearch")
.exec(http("Login")
.post("/mamam/a/masteraccount/login")
.headers(headers_6)
.formParam("username", username)
.formParam("password", password))
// Fetch and save data
.exec(http("Keyframe_request")
.get(uri1 + "/awsset/browse%3Bresource_type=media%3Boffset=1%3Blimit=9")
.headers(headers_12)
.check(jsonPath("$.resources[*].keyframeId").findAll.saveAs("kList"))
)
// added loop and conditions
.doIf(session => session("Keyframe_request").validate[String].map(kList => !kList.contains("-1")))
{
foreach("${kList}", "keyId") {
exec(http("Set_Keyframes")
.get(uri1 + "/keyframes/${kList};width=185;height=103")
.headers(headers_7))
}
}
.exec(http("Logout")
.get("/mam/logout")
.headers(headers_80))
setUp(scn.inject(atOnceUsers(userCount))).protocols(httpProtocol)
}
Throws following Error:
21345 [GatlingSystem-akka.actor.default-dispatcher-13] WARN i.g.http.ahc.AsyncHandlerActor - Request 'Set_Keyframes' failed: status.find.in(200,304,201,202,203,204,205,206,207,208,209), but actually found 400
21346 [GatlingSystem-akka.actor.default-dispatcher-13] DEBUG i.g.http.ahc.AsyncHandlerActor -
>>>>>>>>>>>>>>>>>>>>>>>>>>
Request:
Set_Keyframes: KO status.find.in(200,304,201,202,203,204,205,206,207,208,209), but actually found 400
21390 [GatlingSystem-akka.actor.default-dispatcher-4] INFO io.gatling.http.ahc.HttpEngine - Sending request=Set_Keyframes uri=https://someurl/mamam/keyframes/Vector(167154,%20167035,%20167037,%20167040,%20167029,%20167024,%20167026,%20167022,%20167023);width=185;height=103:
If I have understood correctly you want to take a value from the response and then use it within the next request. Firstly you must save the correct keyframeId.
What was not clear was whether you wanted to select a random keyframeId from your list or multiple keyframes, I have opted to select a random one.
First is that we must apply some jsonPath to our JSON response. This code .check(jsonPath("$.resources[?(#.keyframeId > -1)].keyframeId") will return only a list of keyframeIds which are greater than -1.
Next we select a random one and save it to a variable.
// Fetch and save data
.exec(http("Keyframe_request")
.get(uri1 + "/awsset/browse%3Bresource_type=media%3Boffset=1%3Blimit=9")
.headers(headers_12)
.check(jsonPath("$.resources[?(#.keyframeId > -1)].keyframeId")
.ofType[String]
.findAll
.transform(s => util.Random.shuffle(s).apply(1))
.saveAs("keyframeId"))
Now you just need to check to see if the session variable keyframeId exists and use it to drive your response using ${keyframeId}
.foreach("${IdList}", "id") {
doIf(session => session("id").as[String] != "-1") {
exec(http("ID != -1").get(session => session("id").as[String])
.check(status.is(404)))}
}
I want with my Spray Client Send a post Request with this Content Type
Content-Type: application/x-www-form-urlencoded
I belive that i need to use the object FormData for it :
var fD = new FormData(Seq("UserID:" -> "123", "PWD" -> "123" , "Brand" -> "123"))
But i'm open for other solutions to .
Edit :
I tried sending it this way :
implicit val system = ActorSystem("Client")
var fD = FormData(Map("UserID" -> "123", "PWD" -> "123" , "Brand" -> "123"))
import system.dispatcher // execution context for futures below
val log = Logging(system, getClass)
log.info("Sending test Msg")
val pipeline = sendReceive ~> unmarshal[FormData]
var startTimestamp = System.currentTimeMillis()
val responseFuture = pipeline {
Post(url, fD)
}
responseFuture.onComplete(x=> println(s"Request completed in ${System.currentTimeMillis() - startTimestamp} millis.\n" +
s"Recived :"+x.get)
)
And I'm Getting this error :
spray.httpx.PipelineException: UnsupportedContentType(Expected 'application/x-www-form-urlencoded')
What I'm Done Wrong ? Thank to helpers.
You've basically answered your own question -- you'll want to stick with FormData. A couple of minor things though:
Since you're using the FormData case class, you can drop the
"new".
The companion object for FormData will allow you to pass in
a Map instead of a Seq of tuples.
How can I send multi part form data in post method in play scala
using : scalaVersion:2.11.7
playVersion-2.1.5
You need to do a little code, then you can use it like
val data = MultipartFormData(formFields, "asdasboundarystringas")
WS.url(myUrl).post(data.body)
The code of MultipartFormData you can find on the github: https://gist.github.com/EECOLOR/7649144
UPDATE
Another method, I have been try it with Play 2.4.3
package controllers
import play.api.Play.current
import play.api.libs.ws._
import play.api._
import play.api.mvc._
import com.ning.http.client.AsyncHttpClient
import com.ning.http.client.multipart.FilePart
import com.ning.http.client.multipart.StringPart
import java.io.File
class Application extends Controller {
def index = Action {
val url = "http://symlink.dk/code/php/submit/"
val asyncHttpClient:AsyncHttpClient = WS.client.underlying
val postBuilder = asyncHttpClient.preparePost("http://symlink.dk/code/php/submit/")
val builder = postBuilder.addBodyPart(new StringPart("myField", "abc", "UTF-8"))
.addBodyPart(new StringPart("myField1", "abc1", "UTF-8"))
.addBodyPart(new StringPart("myField2", "abc2", "UTF-8"))
.addBodyPart(new FilePart("myFile", new File("app/controllers/Application.scala")))
val response = asyncHttpClient.executeRequest(builder.build()).get();
Ok(response.getResponseBody)
}
}
Symlink does not verify file part, so I am not sure about it, but fileds definitely was send
UPDATE
With Authentication and file verification
package controllers
import play.api.Play.current
import play.api.libs.ws._
import play.api._
import play.api.mvc._
import com.ning.http.client.AsyncHttpClient
import com.ning.http.client.multipart.FilePart
import com.ning.http.client.multipart.StringPart
import java.io.File
import org.apache.commons.codec.binary.Base64.encodeBase64
class Application extends Controller {
def index = Action {
val url = "http://httpbin.org/post"
val name = "MyUserName"
val password = "MyPassword"
val encodedCredentials =
new String(encodeBase64("%s:%s".format(name, password).getBytes))
val asyncHttpClient:AsyncHttpClient = WS.client.underlying
val postBuilder = asyncHttpClient.preparePost(url)
val builder = postBuilder
.addHeader("Authorization", "Basic " + encodedCredentials)
.addBodyPart(new StringPart("myField", "abc", "UTF-8"))
.addBodyPart(new StringPart("myField1", "abc1", "UTF-8"))
.addBodyPart(new StringPart("myField2", "abc2", "UTF-8"))
.addBodyPart(new FilePart("myFile", new File("app/controllers/Application.scala")))
val response = asyncHttpClient.executeRequest(builder.build()).get();
Ok(response.getResponseBody)
}
}
Echo of posted data:
{
"args": {},
"data": "",
"files": {
"myFile": "package controllers\n\nimport play.api.Play.current\nimport play.api.libs.ws._\nimport play.api._\nimport play.api.mvc._\nimport com.ning.http.client.AsyncHttpClient\nimport com.ning.http.client.multipart.FilePart\nimport com.ning.http.client.multipart.StringPart\nimport java.io.File\nimport org.apache.commons.codec.binary.Base64.encodeBase64\n\nclass Application extends Controller {\n\n def index = Action {\n// val url = \"http://symlink.dk/code/php/submit/\"\n val url = \"http://httpbin.org/post\"\n\n val name = \"MyUserName\"\n val password = \"MyPassword\"\n\n val encodedCredentials =\n new String(encodeBase64(\"%s:%s\".format(name, password).getBytes))\n\n val asyncHttpClient:AsyncHttpClient = WS.client.underlying\n val postBuilder = asyncHttpClient.preparePost(url)\n val builder = postBuilder\n .addHeader(\"Authorization\", \"Basic \" + encodedCredentials)\n .addBodyPart(new StringPart(\"myField\", \"abc\", \"UTF-8\"))\n .addBodyPart(new StringPart(\"myField1\", \"abc1\", \"UTF-8\"))\n .addBodyPart(new StringPart(\"myField2\", \"abc2\", \"UTF-8\"))\n .addBodyPart(new FilePart(\"myFile\", new File(\"app/controllers/Application.scala\")))\n val response = asyncHttpClient.executeRequest(builder.build()).get();\n Ok(response.getResponseBody)\n }\n\n}\n"
},
"form": {
"myField": "abc",
"myField1": "abc1",
"myField2": "abc2"
},
"headers": {
"Accept": "*/*",
"Authorization": "Basic TXlVc2VyTmFtZTpNeVBhc3N3b3Jk",
"Content-Length": "1991",
"Content-Type": "multipart/form-data; boundary=ZUeOacX0k9AyI7O12kXDuV5gucDyh2IcA",
"Host": "httpbin.org",
"User-Agent": "AHC/1.0"
},
"json": null,
"origin": "111.111.111.11",
"url": "http://httpbin.org/post"
}
UPDATE
just for clarification - if you do not need to send file as part of the form then you do not need to access underlying WSClient and can use trivial WS
val url = "http://httpbin.org/post"
val name = "MyUserName"
val password = "MyPassword"
val result = WS.url(url)
.withAuth(name, password, WSAuthScheme.BASIC)
.post(
Map(
"myField" -> Seq("myValue"),
"myField1" -> Seq("myValue1"),
"myField2" -> Seq("myValue2")
)
)
val response = Await.result(result, 10 seconds)
Ok(response.body)
request that this code send:
{
"args": {},
"data": "",
"files": {},
"form": {
"myField": "myValue",
"myField1": "myValue1",
"myField2": "myValue2"
},
"headers": {
"Accept": "*/*",
"Authorization": "Basic TXlVc2VyTmFtZTpNeVBhc3N3b3Jk",
"Content-Length": "51",
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
"Host": "httpbin.org",
"User-Agent": "AHC/1.0"
},
"json": null,
"origin": "111.111.111.11",
"url": "http://httpbin.org/post"
}
Thanks Andriy Kuba!
I've made some changes (WS.client.underlying didn't work for me)
I m running with play 2.4.
package utils
import com.ning.http.client.{AsyncHttpClient, ListenableFuture, Request, Response}
import com.ning.http.client.cookie.Cookie
import com.ning.http.client.multipart.{FilePart, StringPart}
/**
* Created by ozma on 27/05/16.
*/
object WsExtend {
def postFile(url: String,
files: List[(String, String)] = List(),
bodyParams: List[(String, String)] = List(),
cookies: List[Cookie] = List(),
headers: Map[String, String] = Map(),
encoding: String = "UTF-8"): Response = {
postFileAsync(url, files, bodyParams, cookies, headers, encoding).get()
}
def postFileAsync(url: String,
files: List[(String, String)] = List(),
bodyParams: List[(String, String)] = List(),
cookies: List[Cookie] = List(),
headers: Map[String, String] = Map(),
encoding: String = "UTF-8"): ListenableFuture[Response] = {
val asyncHttpClient:AsyncHttpClient = new AsyncHttpClient()
val postBuilder: AsyncHttpClient#BoundRequestBuilder = asyncHttpClient.preparePost(url)
files.foreach(e => postBuilder.addBodyPart(new FilePart(e._1, new java.io.File(e._2))))
bodyParams.foreach(e => postBuilder.addBodyPart(new StringPart(e._1, e._2, encoding)))
cookies.foreach(c => postBuilder.addCookie(c))
headers.foreach(h => postBuilder.addHeader(h._1, h._2))
val request: Request = postBuilder.build()
asyncHttpClient.executeRequest(request)
}
}
This is how I used it with Silhouette CookieAuthenticator
"cookie" is a header called "Set-Cookie" from login response.
WsExtend.postFile(
url=url,
files = List("fileparamname" -> filepath),
bodyParams = List("albumName" -> albumName),
headers = Map("Cookie" -> cookie)