scalareactivemongo

Handling errors as a Future[Result] in ReactiveMongo 16.6


How can I output mongoDB errors in a Result with ReactiveMongo (16.6)? I've spent virtually the whole day looking through samples but have not been able to achieve this as of yet. The error section of the documentation returns a Future[Unit] rather than a Future[Result]. And every other example/sample that I can find either is outdated or does not do this; example_1, example2

Here is what I would like to do:

  def updateById(collName: String, id: BSONObjectID) = authAction.async(parse.json) { implicit request: Request[JsValue] =>

    val oWriteJso = request.body.asOpt[JsObject]
    lazy val qJso = Json.obj("_id" -> id)

    val res = oWriteJso.map(
      wJso => mongoRepo.update(collName)(qJso, wJso)().recoverWith {
        case WriteResult.Code(11000) => Future.successful(BadRequest("it went bad"))
        case _ => Future.successful(BadRequest("also bad"))
      }
    )

    res

  }

Of course with the function signature as recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] this code above will return an error as it needs to return a Future[WriteResult]. But how then would I be able to put any error messages, codes, etc (from mongoDB) into a Result?


Solution

  • The documentation indicates how to recover a Future[WriteResult]:

    .recover {
      case WriteResult.Code(11000) =>
        // if the result is defined with the error code 11000 (duplicate error)
        println("Match the code 11000")
    
      case WriteResult.Message("Must match this exact message") =>
        println("Match the error message")
    
      // ...
    }
    

    Thanks to Future combinators (not specific to ReactiveMongo), it can be used whatever is the type of the successful value to be lifted inside the Future.

    def foo[T](future: Future[WriteResult], recoveredValue: => T)(success: WriteResult => T): Future[T] = future.map(success).recover {
      case WriteResult.Code(11000) =>
        // if the result is defined with the error code 11000 (duplicate error)
        recoveredValue
    
      case WriteResult.Message("Must match this exact message") =>
        recoveredValue
    
    }