factoring out common headers

Hi,

What’s the idiomatic way of sharing headers between scenarios that have actions of different types?

If we define our actions in a list, map over it to add the common headers and then create a chain out of them we would naively write something like:

lazy val actions = List (

createTokenAction, getTokenAction, updateTokenAction(“REDEEMED”, 200),
findTokenAction, updateTokenAction(“EXPIRED”, 403), deleteTokenAction
)

val firstAction :: actionsWithHeaders = actions map (_ headers additionalHeaders)

override lazy val chain = actionsWithHeaders.foldLeft(exec(firstAction)) {
(c, a) => c.exec(a)

…which won’t compile. The type of actions is

List[AbstractHttpRequestBuilder[_ >: HttpRequestBuilder with HttpRequestWithParamsBuilder : AbstractHttpRequestBuilder[_ >: HttpRequestBuilder with HttpRequestWithParamsBuilder]]]

because we have both with and without params HttpBuilders and then the compiler cannot find any exec() with that type signature.

My guess is that there’s a much easier solution to factor out logic that you want applied to your actions. Simple pointers to idiomatic examples might suffice.

Thank you.

Vasco

Hi Vasco,

Please note that using a foldLeft to chain your requests in not required, and has become harder to achieve since import bootstrap._ and emptyChain have been removed in Gatling 2.

You can chain your request that way :

val actions: List[HttpRequestBuilder] = List(...) // I expect here that they're plain http requests and does not include other DSL elements val actionsWithHeaders = actions.map(_ headers additionnalHeaders).map(exec) val chain = exec(actionWithHeaders: _*) //Constrain a List to var-args

Another way could be to create custom functions that are simply “wrappers” for the underlying HTTP request, abstracting away common actions.
Let’s take an example:
For each kind of static resource (CSS, JS, images), we have a different set of headers that are used, but we don’t want to keep repeating them again and again.
Plus we don’t need “clever” names for the resources request names, the name of the resource suffices.
We can do something like that to abstract those commons patterns away :

`
def nameFromUrl(url: String) = url.split("/").last

def requestResource(url: String, headers: Map[String, String]) = http(nameFromUrl(url)).get(url).headers(headers)

val cssHeaders: Map[String, String] = Map(…)

val jsHeaders: Map[String, String] = Map(…)

val imageHeaders: Map[String, String] = Map(…)

def cssResource(url: String) = requestResource(url, cssHeaders)

def jsResource(url: String) = requestResource(url, jsHeaders)

def imageResource(url: String) = requestResource(url, imageHeaders)

`

If you happend to use your additionalHeaders a lot, for requests following a same pattern, it could prove useful to abstract this behaviour in the way I suggested.

Hope this helps !

Cheers,

Pierre

Hi Pierre,

Thanks for your message.

If one of the actions is a POST you cannot have actions as a list of HttpRequestBuilder and thus cannot use exec in that way.

val actions = List(somePostAction, someGetAction)
val actionChain = actions.map(_ headers additionalHeaders).map(exec(_))
override lazy val chain = exec(actionChain: _*)

We can work around this issue, no problem. I was just curious if there was an obvious, more idiomatic way of dealing with this use case.

Thank you.

Kind regards,

Vasco

Even if GET and POST requests have a slightly different hierarchy, they all share a common super class : AbstractHttpRequestBuilder.
If the Scala compiler seems to get in your way, can always constrain the type of actions to their common superclass :

val actions: List[AbstractHttpRequestBuilder[_]] = List(somePostAction, someGetAction)

Oh,

It builds fine with

val actions: List[AbstractHttpRequestBuilder[_ <: AbstractHttpRequestBuilder[_]]] = List(somePostAction, someGetAction)

…although Intellij’s Scala plugin marks the exec(_) call in red.

I’ve seen it mistakenly mark good code as bad by not taking full advantage of implicits in scope, but that does not seem to be the case.

Cheers,

Honestly, it has been a while since I relied with confidence on IntelliJ error highlighting for Scala…