0

Currently working on a server-side front-end Scala Play app that does a lot of grabbing of HTML snippets and JSON from many other web apps before piecing everything together and sending it in a response to the browser.

Since a lot of these other web apps are legacy, they don't expose nice REST APIs and need to be called as if browsers/clients are directly calling them. This means they require things like session ID, stateKey, plus various headers and cookies, etc, which they use for tracking, authentication, etc. We are in the process of slowly re-writing our systems to be nicer, but in the meantime, there are still a lot of these apps that this front-end needs to work with.

In Play, the Request object passed to a Controller is immutable and conveniently has all the aforementioned data. We didn't want our controllers to hold all the logic for calling the various web apps, so we've put them in various "Service" classes.

The question I have is, when calling methods on these Services, is it reasonable to pass a Request object to them (along with other data)? It seems like a grey area because while some might call it a code-smell, in the case of a front-end app like ours which does a lot of (essentially) proxying, it also seems reasonable.

To get things started, a few options are:

A. Passing the entire request

// Service method
def getData(req: Request): HtmlSnippet = {
  Ws.url(serviceAddress)... // configure request using req
}

// Call from controller
getData(req)

B. Pass everything needed one by one

// Service method
def getData(loadBalancerCookie: Cookie, StateKey: StateKey, headers: Seq[Header], sessionId: String .. ): HtmlSnippet = {
  Ws.url(serviceAddress)... // configure request using params
}

// Call from controller
val lbCookie = req.lbCookie
val stateKey = req.stateKey
...
getData(lbCookie, stateKey, headers, ..)

C. Pack everything into a separate object

// Custom object

case class GetDataArgs(loadBalancerCookie: Cookie, StateKey: StateKey, headers: Seq[Header], sessionId: String)

// Service method
def getData(args: GetDataArgs): HtmlSnippet = {
  Ws.url(serviceAddress)... // configure request using GetDataArgs
}

// Call from controller
val getDataArgs = GetDataArgs(req.lbCookie, req.stateKey, ...)
getData(getDataArgs)

Other suggestions are welcome, as I'm trying to find a good balance between ease of maintenance, good design, and comprehensibility.

  • Suppose your "Service" classes would get re-used in a desktop application (something that doesn't receive user input as Request instances), would it make sense to create a Request instance in the caller of getData to provide all the needed information? – Bart van Ingen Schenau Oct 9 '14 at 14:17
  • I suppose in that case, you would end up creating something in the caller of getData that looks very similar but not quite. It needs certain things that are very HTTP-specific, such as, isSecure and related header values. – lloydmeta Oct 14 '14 at 8:09
  • Depending on the similarity, I would either go for A or C. – Bart van Ingen Schenau Oct 14 '14 at 8:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.