gatlingscala-gatling

building request body from optional checks


I'm trying to model a scenario where an initial request will provide several different lists of Ids, then a later request needs to submit the values in these lists (if they exist) as part of it's JSON payload. None of the lists is guaranteed to be in the response, and if it isn't, then there is no corresponding entry at all for it in the later JSON.

For example, call 1 might return 3 different lists of Ids that can be saved for later calls...

.check(
  jsonPath("$..manager").findAll.optional.saveAs("managemerIds"),
  jsonPath("$..employee").findAll.optional.saveAs("employeeIds"),
  jsonPath("$..temp").findAll.optional.saveAs("tempIds")      
)

Later I need to submit these as a request body formatted like

{"managers":"${managerIds.jsonStringify()}",
 "employees":"${employeeIds.jsonStringify()}",
 "temps":"${tempIds.jsonStringify()}"}

but if one of the lists of Ids is empty, then it can't be submitted in the JSON at all - ie: if there were no tempId's from the first request, then the JSON payload needs to look like

{"managers":"${managerIds.jsonStringify()}",
 "employees":"${employeeIds.jsonStringify()}"}

I could get this working by using a transformOption on the check to set the session variable to an empty list and then have conditional building of the JSON payload by doing something like

jsonPath("$..temp").findAll.transformOption(ids => ids.orElse(Some(Seq.empty[String])).success).saveAs("tempIds"))

but I was hoping for something more scala idiomatic using Options.

I can generate the required JSON for the body this way with something like

private def createPayload(
    managers: Option[String] = None, 
    employees: Option[String] = None, 
    temps: Option[String] = None) : String = {

        Map("managers" -> managers,
            "employees" -> employees,
            "temps" -> temps
        ).foldLeft(JsObject.empty){ case (result, (key, values)) => {
        values match {
          case Some(ids) => result ++ result.transform((__ \ key).json.put(JsString(ids))).get
          case None => result
      }
    }}.toString()

but I can't work out a way to just pass the option that results from attempting to resolve the session variable


Solution

  • With newer versions of Gatling, it's now possible to use Pebble here is how you can achieve it easily:

      body(PebbleStringBody(
      """
    {
    
        {% if managers %} "managers": [
            {% for value in managers %}
            
                "id":"{{value.id}}"
            {% if loop.last %}{% else %} , {% endif %}
            {% endfor %}
            ]
        {% endif %}
        
    }
    """))
    

    Mind the PebbleStringBody instead of the traditional StringBody You can then achieve several operations including conditioning and loop.