喷涂请求 - 仅在嵌套期货之后完成请求

时间:2015-02-01 14:07:20

标签: scala akka spray spray-client

新的喷雾和斯卡拉。现在几天都在努力做到正确。

我试图将facebook oauth2登录+用户登录详细信息合并到数据库中,以防同一用户以不同方式登录(user / pass或fb login)。

在喷涂路线片段下方粘贴。

  path("facebook") {
    post{
      entity(as[JObject]) { json =>
        val fb: FacebookAuthModel = json.extract[FacebookAuthModel]
        complete {

          //Get user details from fb oauth2
          val fbUser = fbAuth.getIdentity(fb) match {
            case Right(user: User) => user
            case Left(error: Failure) => throw new FailureException(error)
          }

          //Check if user is already present either by fb id or email
          val userFuture = userRepo(FetchUserByFacebook(fbUser.facebook.get,fbUser.email))

          userFuture.map {
            case u: User => {

              //user present but fb id not attached yet
              if (u.facebook.isEmpty) {
                //update fb id for the user - fire to actor and forget, i.e no callback to sender
                userRepo(UpdateFacebookId(u.id.get, fbUser.facebook.get))
              }

              //complete request with a token - request(1)
              AuthToken(token=jwt.createToken(u))
            }
            case None => {

              //first time user using fb login
              userRepo(CreateUser(fbUser)).map {

                //complete request with the token - request(2)
                case createdUser: User => AuthToken(token=jwt.createToken(createdUser))

                case None => throw new FailureException(Failure("Not able to CreateUser", FailureType.Unauthorized))
              }
            }
          }
        }  
      }
    }
  } 

除非第一次使用fb登录用户(请参阅请求(2)),否则一切正常。
在嵌套未来完成之前,请求将以空响应完成。

我尝试了flatMapping来自userFuture的结果,然后在其上使用onComplete来给出相应的响应,但是它没有工作。

知道如何使用令牌成功完成请求(request(2))吗?

1 个答案:

答案 0 :(得分:1)

如果代码执行路径中的两个分支之一可能导致Future,那么在处理userFuture时,您必须将此代码编码为最小公分母。这意味着在flatMapuserFuture,并且在您没有明确的第二个Future.successful来处理的情况下使用Future。这条线上的东西:

def handleUserResult(a:Any):Future[AuthToken] = a match{
  case u:User =>              
    if (u.facebook.isEmpty) {                
      userRepo(UpdateFacebookId(u.id.get, fbUser.facebook.get))
    }              
    Future.successful(AuthToken(token=jwt.createToken(u)))

  case None =>              
    userRepo(CreateUser(fbUser)).map {
      case createdUser: User =>
        AuthToken(token=jwt.createToken(createdUser))

      case None => 
        throw new FailureException(Failure("Not able to CreateUser", FailureType.Unauthorized))
    }
}

定义该方法后,您可以在userResult上使用它,如下所示:

userResult.flatMap(handleUserResult)

我没有检查此代码是否存在编译问题。我更倾向于展示用于处理两个案例的flatMap的一般方法,一个产生另一个Future而一个产生另一个{{1}}。