Play! Framework composing actions with async web r

2019-08-08 13:26发布

问题:

I'm quite new to Scala I'm trying to access Instagram API from Play! and Scala.

def authenticate = Action {
request =>
  request.getQueryString("code").map {
    code =>
      WS.url("https://api.instagram.com/oauth/access_token")
        .post(
        Map("client_id" -> Seq(KEY.key), "client_secret" -> Seq(KEY.secret), "grant_type" -> Seq("authorization_code"),
          "redirect_uri" -> Seq("http://dev.my.playapp:9000/auth/instagram"), "code" -> Seq(code))
      ) onComplete {
        case Success(result) => Redirect(controllers.routes.Application.instaline).withSession("token" -> (result.json \ "access_token").as[String])
        case Failure(e) => throw e
      }
  }
 Redirect(controllers.routes.Application.index)

}

When app executes, the last redirect happens before redirect in case of Success. Tell me please, how to avoid it. And Also, let me know about bad practices that is in my code.

回答1:

With Play, you return a result - you don't send a result. The onComplete method attaches a method that does something, but doesn't return anything (note its return value is Unit, ie, void). After attaching that callback, you are then returning Redirect on the last line, which is not what you want to do. Instead you want to map the future that you get back from the WS invocation, and return that future. And to return a future in Play, you need to use the Action.async builder. eg:

def authenticate = Action.async { request =>

  request.getQueryString("code").map { code =>

    WS.url("https://api.instagram.com/oauth/access_token").post(
      Map(
        "client_id" -> Seq(KEY.key),
        "client_secret" -> Seq(KEY.secret),
        "grant_type" -> Seq("authorization_code"),
        "redirect_uri" -> Seq("http://dev.my.playapp:9000/auth/instagram"),
        "code" -> Seq(code)
      )
    ).map { result =>

      Redirect(controllers.routes.Application.instaline)
        .withSession("token" -> (result.json \ "access_token").as[String])

    }
  }.getOrElse {
    Future.successful(Redirect(controllers.routes.Application.index))
  }
}