Sending JSON request bodies

Hi,

I’m wondering if there’s a simple way to marshall a Java/Scala object and send it as a POST or PUT request body. https://github.com/excilys/gatling/wiki/HTTP#wiki-request-body assumes that the requests are already in JSON format, either as Strings, or as request body files, or as SSPs, but it could be useful to marshall straight from a Java/Scala object.

Thanks,
Emerson

Hi,

You can pass a function to byteArrayBody where you can call whatever marshaling engine call you want.
We’ll probably enrich this feature in order to make things easier for non plain text formats such as BSON, protobuf or GWT-RPC.

However, I fail to see the point for JSON that’s a plain text format. Could you explain, please?

Cheers,

Stéphane

Hi.

Thanks for the quick answer. I agree that using byteArrayBody isn’t a good fit for a plain text format.

Sure, I can give some background. I’ve got a Java API exposed using Spring MVC, so my requests and responses are all defined as Java objects. In order to test this API with as little effort as possible, I’d like to use these Java clases from Scala, call their setters, and specify the object itself as the thing to marshall and send. For example, imagine some syntax like

http("request").post("uri").objectBody(newObject(foo)).asJSON

Thanks for the quick answer. I agree that using byteArrayBody isn't a good
fit for a plain text format.

That's not what I meant.
I meant that I don't see the point of going through all the marshaling
hassle for a plain text format such as JSON. Going this way would be much
more complex (marshaling code, shipping DTO classes) and less efficient
that using a plain text template.
Note that you can also pass a body with body(Session => String)

Sure, I can give some background. I've got a Java API exposed using Spring
MVC, so my requests and responses are all defined as Java objects. In order
to test this API with as little effort as possible, I'd like to use these
Java clases from Scala, call their setters, and specify the object itself
as the thing to marshall and send. For example, imagine some syntax like

http("request").post("uri").objectBody(newObject(foo)).asJSON

where newObject builds the object to send, objectBody specifies the
Scala/Java object, and asJSON does the serialization.

asJSON already exists, but it just sets the ContentType. Changing its
responsibility would break the existing API.
You'd need a jsonBody that would do the serialization.

The two alternatives right now that I can see are to

1. Manually pass all my objects through Jackson to get their JSON
equivalent, and copy the produced JSON to request body files. The problem
here, besides the manual labour, is that those request body files would
need to be maintained should the objects change. Using objects I could find
usages when I modify the object and updated my Scala test code accordingly.

The manual labour can be reduced thanks to the recorder that can dump the
raw file bodies for you. But yes, changing requests comes with a
maintenance cost. Only a browser-like tool, like Selenium/webkit, would be
able to reduce this cost, but it would ill fitted for stress testing (too
CPU consuming, would need a 50 server cluster).

2. Use the standard body() call and replace newObject() with
newObjectAsString(), which would somehow call Jackson to give me back a
String representation of the passed object (not something I'm comfortable
with just yet given how completely new I am to both Gatling and Scala)

And yet, if you really want to go that way, that's the way to go :wink:
Learning Scala basics is not that hard, Twitter Scala School is a good
starter.http://twitter.github.com/scala_school

So, you'd just have to write something like :

// There's already a Jackson ObjectMapper instance in Gatling that you can
reuse
import
com.excilys.ebi.gatling.core.check.extractor.jsonpath.JsonPathExtractor.mapper

.body(session =>
   // build your POJO with values from the session
   val myPOJO = ...
   mapper.writeValueAsString(myPOJO)
)

And that's it!

Cheers,

Stéphane

Thanks for all the info, really useful, and it’ll hopefully be useful to whoever digs up this conversation down the line.

I’ll try the SSP method to avoid the marshalling hit, and experiment with the ObjectMapper route if I have time.

Cheers,
Emerson

Hi Stéphane & Emerson,
I am a new user of Gatling & Scala & I have some question related to sending Json strings as request bodies.
Here is my problem:
I have a json file containing multiple json blobs, separated by newlines.
I want to send as many as POSTs as there are entries in that Json file with different request bodies i.e each POST has one Json string from that Json file.

I could find body().asJson & fileBody().asJson. But the problem is fileBody() takes the contents of the entire Json file.

Can I do something like:
for(line : “myJsonfile.Json”) {

http("String body").post("my.post.uri")
  .body(${line}).asJSON


}

So not sure how to achieve the above scenario.

Thanks,
Debasis

Hi,

So you have one json object per line, right?
Which version of Gatling do you use?

Stéphane

Hi Stéphane, thanks for the response.

I am using 1.5.2.

Also I tried to do something like putting the json blobs in a single column tsv/ssv file & use feed() & body().asJSON to populate the body of the POST. But Looks like the resultant JSON in the POST is malformed. Specifically wherever there is a blank value i.e “myValue”:"" then it truncates the double “” to one ". And also one more scenario is:

{“t”:“voipmonitor”, … is truncated to {t":“voipmonitor”, … The {“t” is truncated to {t" .

Is there something wrong I am doing here?

The exact Json blob is:

{“t”:“monitor”, “source”:“monitor”, “caller”:"+176", “callername”:"+76976", “callerip”:“x.x.x.x”, “sippcalledip”:“x.x.x.x”, “called”:"+76", “duration”:12, “progress_time”:2, “first_rtp_time”:2, “connect_duration”:3, “calltimestamp”:1380052560, “fbasename”:“669eb3180fa52f64103698c665d31419@c.c.c.c”, “hostsid”:“ade4f70a78f5b3ff123be73”, “oname”:“606258145d5dd6c3c”, “callsegmentsid”:"", “s_dt”:“s3://com.twilio.dev.logs/hurl/2013-09-24/669eb3180fa52f64103698c665d31419@16ade4f70a78f5b3ff123be73.ap”, “call_id”:"", “client”:"", “roles”:“url”, “s_region”:“dev”, “availability_zone”:“us-1d”, “providerd”:“fe7861f564cec468cf20132222”, “accountsid”:“8e2339cc04ba82dac696e”, “sighup”:0, “lastresponse”:“0 OK”, “lastum”:200, “bye”:3, “anged”:“callee”, “a_ua”:"", “b_ua”:“risk PX”, “a_index”:0, “a_received”:511, “a_lost”:0, “a_avgjitter”:0.136228, “a_maxjitter”:0.867274, “a_payload”:0, “a_sl1”:0, “a_sl2”:0, “a_sl3”:0, “a_sl4”:0, “a_sl5”:0, “a_sl6”:0, “a_sl7”:0, “a_sl8”:0, “a_sl9”:0, “a_sl10”:0, “a_d50”:0, “a_d70”:0, “a_d90”:0, “a_d120”:0, “a_d150”:0, “a_d200”:0, “a_d300”:0, “a_saddr”:“208.93.226.14”, “a_lossr_f1”:0, “a_burstr_f1”:0, “a_mos_f1”:4.5, “a_lossr_f2”:0, “a_burstr_f2”:0, “a_mos_f2”:4.5, “a_lossr_adapt”:0, “a_burstr_adapt”:0, “a_mos_adapt”:4.5, “b_index”:0, “b_received”:511, “b_lost”:0, “b_avgjitter”:0.136228, “b_maxjitter”:0.867274, “b_payload”:0, “b_sl1”:0, “b_sl2”:0, “b_sl3”:0, “b_sl4”:0, “b_sl5”:0, “b_sl6”:0, “b_sl7”:0, “b_sl8”:0, “b_sl9”:0, “b_sl10”:0, “b_d50”:0, “b_d70”:0, “b_d90”:0, “b_d120”:0, “b_d150”:0, “b_d200”:0, “b_d300”:0, “b_saddr”:“208.93.226.14”, “b_lossr_f1”:0, “b_burstr_f1”:0, “b_mos_f1”:4.5, “b_lossr_f2”:0, “b_burstr_f2”:0, “b_mos_f2”:4.5, “b_lossr_adapt”:0, “b_burstr_adapt”:0, “b_mos_adapt”:4.5}

Hi

Was any solution prescribed for the above scenario for POSTing a URL using one json message body per line from a file ?

Thanks
Narayanan