Scala - создание http-запроса WS - PullRequest
0 голосов
/ 15 мая 2018

ОБНОВЛЕНО: Метод возвращает тип ЛЮБОЙ, а не тип Future [строка].Требовать возврата типа String.

Я делаю http-запрос с использованием библиотеки play.ws 2.6.Ранее это было сделано с помощью запроса curl, но при этом используется только базовая аутентификация.

Ниже приведен мой код, и я пытаюсь вернуть строку json из этой функции для десериализации в другом методе.

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.
} 

При запуске выдает ошибку:

[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

Я пытаюсь получить в идеале:

  • Строка возврата (case case и jsonметод для распаковки строки)
  • Синхронный запрос (если асинхронный, мне нужно подождать, чтобы завершить выполнение приложения)
  • Безопасный (позволяет использовать токены для проверки)

Ценю любую помощь!

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Авторизация также может быть вводом в функцию или извлечена из переменных среды в методе (намного проще в управлении).

Просто необходимо использовать .body при вызове Await, который преобразует вывод в строку общего типа.

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
    }
}
0 голосов
/ 15 мая 2018

Вот функция, которую я использую:

// 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

}

Я бы создал case class прямо как: .map(jsValue => handleJson(jsValue.validate[YourModel])) // or create a model of it (instead) вместо .map(Json.prettyPrint)

Редактировать

Вот пример 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)
    }
  }

Исключение создано мной.

...