Вызов нескольких веб-сервисов из игры 2

Я новичок в play2.0-Scala, и мне нужно вызвать несколько веб-сервисов для создания HTML-страницы.

Прочитав страницу Play WS API и очень интересная статья Садека Дроби Я до сих пор не знаю, как лучше всего это сделать .

В статье показаны некоторые фрагменты кода, которые я не совсем понимаю как новичок в Play.

Рисунок 2 на странице 4:

val response: Either[Response,Response] =
  WS.url("http://someservice.com/post/123/comments").focusOnOk

val responseOrUndesired: Either[Result,Response] = response.left.map {
  case Status(4,0,4) => NotFound
  case Status(4,0,3) => NotAuthorized
  case _ => InternalServerError
}

val comments: Either[Result,List[Comment]] = 
responseOrUndesired.right.map(r => r.json.as[List[Comment]])

// in the controller
comment.fold(identity, cs => Ok(html.showComments(cs)))

Что делает последняя строка с fold? Должно ли comment быть comments? Разве я не сгруппировал последний оператор в блок Async?

На рис. 4 показано, как объединить несколько вызовов ввода-вывода с одним for-выражением:

for {
  profile <- profilePromise
  events <- attachedEventsPromise
  articles <- topArticlesPromise
} yield Json.obj(
  "profile" -> profile,
  "events" -> events,
  "articles" -> articles )

}

// in the controller
def showInfo(...) = Action { rq =>
  Async {
    actorInfo(...).map(info => Ok(info))
  }
}

Как я могу использовать этот фрагмент? (Меня немного смущает дополнительный-} после for-выражения.) Должен ли я написать что-то вроде этого?

var actorInfo = for {                // Model
  profile <- profilePromise
  events <- attachedEventsPromise
  articles <- topArticlesPromise
} yield Json.obj(
  "profile" -> profile,
  "events" -> events,
  "articles" -> articles )

def showInfo = Action { rq =>         // Controller
  Async {
    actorInfo.map(info => Ok(info))
  }
}

Как лучше всего объединить фрагменты рисунков 2 и 4 (обработка ошибок + композиция неблокирующих вызовов ввода-вывода)? (например, я хочу создать код состояния ошибки 404, если какой-либо из вызываемых веб-сервисов выдает ошибку 404).

Может быть, кто-то знает полный пример вызова веб-сервисов в play framework (не могу найти пример в приложениях play Sample или где-либо еще).


person Sonson123    schedule 03.09.2012    source источник


Ответы (1)


Я должен сказать, что статья неверна в примере, показанном на рисунке 2. Метода focusOnOk не существует в Play 2.0. Я предполагаю, что тогда автор статьи использовал предварительную версию Play 2.

Что касается comment, то да, должно быть comments. fold в операторе работает с Either. Он принимает 2 функции в качестве параметров. Первая — это функция, которую следует применять, если это левое значение. Вторая — это функция, которую следует применять, если это правильное значение. Более подробное объяснение можно найти здесь: http://daily-scala.blogspot.com/2009/11/either.html

Итак, что делает линия. Если у меня есть левое значение (что означает, что я получил нежелательный ответ), примените встроенную функцию identity, которая просто возвращает вам значение. Если он имеет правильное значение (что означает, что я получил ответ OK), создайте новый результат, который каким-то образом покажет комментарии.

Что касается Async, на самом деле это не асинхронно. focusOnOk — функция блокировки (пережиток старых Java-дней Play 1.x). Но помните, что это недействительный код Play 2.

Что касается рисунка 4, конечная } на самом деле потому, что это частичная альтернатива тому, что на рисунке 3. Вместо многочисленных обещаний flatMap. Вместо этого вы можете сделать для понимания. Кроме того, я думаю, что это должно быть userInfo(...).map вместо actorInfo(...).map.

Документация по Play, на которую вы ссылаетесь, уже показывает вам полный пример.

def feedTitle(feedUrl: String) = Action {
  Async {
    WS.url(feedUrl).get().map { response =>
      Ok("Feed title: " + (response.json \ "title").as[String])
    }
  }  
}

получит все, что находится по адресу feedUrl, и вы map сделаете что-то с response, у которого есть поле status, которое вы можете проверить, чтобы увидеть, было ли это 404 или что-то еще.

С этой целью рисунки 3 и 4 вашей связанной статьи должны дать вам отправную точку. Таким образом, у вас будет что-то вроде,

def getInfo(...) : Promise[String] = {
  val profilePromise = WS.url(...).get()
  val attachedEventsPromise = WS.url(...).get()
  val topArticlesPromise = WS.url(...).get()

  for {
    profile <- profilePromise
    events <- attachedEventsPromise
    articles <- topArticlesPromise
  } yield {
    // or return whatever you want
    // remember to change String to something else in the return type
    profile.name 
  }
}

def showInfo(...) = Action { rq =>
  Async { 
    getInfo(...).map { info =>
      // convert your info to a Result
      Ok(info)
    }
  }
}
person thatsmydoing    schedule 03.09.2012
comment
Спасибо за ответ, теперь стало намного понятнее :-). Но как я могу создать страницу с ошибкой, когда f.ex. вызов в getInfo() приводит к ошибке 500? - person Sonson123; 03.09.2012
comment
В этом случае вы можете вернуть Option в getInfo, затем вернуть None, если вы получили ошибку, в противном случае вернуть Some, содержащее фактическое значение, если это не ошибка. Затем вы можете выполнить сопоставление с шаблоном в контроллере и вернуть InternalServerError, если это было None или OK в противном случае. - person thatsmydoing; 04.09.2012
comment
Ок, большое спасибо за подробный ответ! Мне нужны два разных кода ошибки (404, 500), поэтому я попытаюсь вернуть Either и использовать response.status в getInfo и надеюсь, что это сработает... - person Sonson123; 04.09.2012