crowgers
crowgers

Reputation: 274

Scala - making a WS http request

UPDATED: Method is returning type ANY rather than type Future[string]. Require return of type String.

I'm making a http request using the play.ws library 2.6. This was previously done with a curl request but this only uses basic authentication.

Below is my code and I'm trying to return a json string from this function to be deserialised in another method.

import java.io.{File, InputStream}
import java.nio.file.Paths
import javax.inject._

import org.apache.commons.io.FileUtils

import play.api._
import play.api.http.HttpEntity
import play.api.libs.ws._
import play.api.mvc._
import play.api.Play.current

import scala.collection.mutable.ListBuffer
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

import sys.process._

@Singleton
class BuildService @Inject() (
ws: WSClient,
ec: ExecutionContext,
config: Configuration) {

    def bbApiRequest(requestUrl: String, timeout: FiniteDuration): 
        Future[String] = {
        val request = ws
            .url(requestUrl)
            .withAuth(
                "user", 
                "pw1234",
                WSAuthScheme.BASIC)
            .get()
        Await.result(request, timeout)
        val returner = request.map(_.json)
    } // <-- line 72 in below error points here.
} 

When run it produces the error:

[error] C:\my_path\app\services\BuildService.scala:72: type mismatch;
[error]  found   : Unit
[error]  required: scala.concurrent.Future[String]
[error]         }
[error]         ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[info] Compiling 1 Scala source to C:\my_path\restapi\target\scala-
       2.12\classes...
[error] C:\my_path\restapi\app\services\BuildService.scala:72: type 
        mismatch;
[error]  found   : Unit
[error]  required: scala.concurrent.Future[String]
[error]         }
[error]         ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed

I'm trying to get ideally:

Appreciate any help!

Upvotes: 0

Views: 1547

Answers (2)

crowgers
crowgers

Reputation: 274

The authorization can also be inputs into the function or retrieved from environment variables within the method (much easier to manage).

Simply needed to use .body on the Await call, which converts the output to generic type string.

package utils

import javax.inject._

import play.api._
import play.api.http.HttpEntity
import play.api.libs.ws._
import play.api.mvc._
import play.api.Play.current

import scala.collection.mutable.ListBuffer
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

import sys.process._

@Singleton
class HTTPRequest @Inject() (
ws: WSClient,
ec: ExecutionContext,
config: Configuration) {

    def bbApiRequest(requestUrl: String, timeout: FiniteDuration) = {
        val request = ws
            .url(requestUrl)
            .withAuth(
                "user", 
                "PW123", 
                WSAuthScheme.BASIC)
            .get()
        Await.result(request, timeout).body
    }
}

Upvotes: 0

pme
pme

Reputation: 14803

Here is the function I use:

// first work with Futures the Play Controller will support that!
def bbApiRequest(requestUrl: String): Future[String] = {

  // call the webservice with basic authentication
  wsClient.url(requestUrl)
    .withAuth("tester", "pwd123", WSAuthScheme.BASIC)
    .get()
    .map(checkStatus) // function that evaluates the HTTP Status
    .map(_.json) // get the json
    .map(Json.prettyPrint) // get it as string

}

I would create a case class directly like: .map(jsValue => handleJson(jsValue.validate[YourModel])) // or create a model of it (instead) instead of .map(Json.prettyPrint)

Edit

Here an example of checkStatus:

  protected def checkStatus(resp: WSResponse): WSResponse = {
    resp.status match {
      case Status.OK => resp
      case Status.NOT_FOUND => throw WebNotFoundException()
      case Status.FORBIDDEN | Status.UNAUTHORIZED => throw WebAccessForbiddenException()
      case Status.NOT_ACCEPTABLE => throw WebNotAcceptableException()
      case _ => throw WebBadStatusException(resp.status + " - " + resp.statusText.toString)
    }
  }

The Exception are created by myself.

Upvotes: 1

Related Questions