El manejo de errores cuando la combinación de múltiples WS llamadas en un resultado

StackOverflow https://stackoverflow.com//questions/12666169

  •  11-12-2019
  •  | 
  •  

Pregunta

Estoy aprendiendo scala, jugar, servicios web y todos a la vez, así que tengan paciencia conmigo.Me he puesto un poco de agregador de servicio que combina un clima y el servicio web de google de geocodificación y lugares de servicios web.Tengo algo de trabajo, pero estoy un poco confundido sobre la forma adecuada de manejar los errores.(He publicado el código al final del post).

Por lo que los lugares de la api utiliza lat/long y por lo que utilizar la api de geocodificación para obtener lat/long del código postal.Cuando el procesamiento de la respuesta de la llamada a la api de geocodificación termino con un (Option[String], Option[String]) (celebrado en el maybeLoc val).En el interior del partido de la declaración de que los cheques maybeLoc, si termina siendo (None, None), Vuelvo Promise() porque tengo que devolver un Promise desde el flatmap llamada.

Tengo dos preguntas al respecto:

1.) ¿Cuál es la forma correcta de manejar el caso de no ser capaz de hacer que cualquier transformación, mientras que en el interior de uno de estos flatMap o mapa de llamadas?Esto me obliga a volver una promesa, sino hacer un vacío Promise que se acaba el tiempo cuando voy a canjear parece una idea realmente mala.

2.) Estoy en lo cierto al suponer que la llamada a la Promise() hace una promesa vacía objeto de que siempre fuera de tiempo al intentar canjearlo?Realmente no podría decir de la scaladoc y no pude encontrar nada al respecto de google.

Espero que mis preguntas tengan sentido para usted, y son lo suficientemente claros.Aquí está el código:

def bothAsJson(zipcode:String) = Action {
    val promiseOfLoc = Geocode.buildUrlFor(zipcode).get()
    val promiseOfWeather = Weather.buildUrlFor(zipcode, "json").get()

    val result = promiseOfLoc.flatMap { locResp => 
        val maybeLoc = Geocode.extractLocation(locResp.body.toString())
        maybeLoc match {
            case (Some(lat), Some(lng)) => {
                val promiseOfPlaces = Places.buildUrlFor(lat,lng).get()
                promiseOfPlaces.flatMap { placesResp =>
                    promiseOfWeather.map { weatherResp =>
                        (weatherResp.body.toString(), placesResp.body.toString())
                    }
                }
            }
            case _ => Promise()
        }
    }

    Async {
        result.orTimeout("Timeout!", 2000).map {response =>
            response.fold(
                result => Ok("Got:\n\nweather:\n" + result._1 + "\n\nplaces:\n" + result._2),
                timeout => InternalServerError(timeout)
            )
        }
    }
}
¿Fue útil?

Solución

Si usted consigue (None, None) no debería estar buscando a tiempo de espera, pero volver otro mensaje de error, creo.He dado un ejemplo a continuación.

Creo que usted necesita OptionT a partir de scalaz 7.Me gustaría escribir esto como:

import scalaz._
import Scalaz._

def bothAsJson(zipcode:String) = Action {
    val promiseOfLoc = Geocode.buildUrlFor(zipcode).get.map { Option(_.body.toString()) }
    val promiseOfWeather = Weather.buildUrlFor(zipcode, "json").get
       .map{ lockResp => 
           val (lat,lng) = Geocode.extractLocation(locResp.body.toString())
           (lat |@| lng).tupled
       }
    def buildPlaces(lat: String, lng: String) = Places.buildUrlFor(lat,lng).get
       .map { Option(_.body.toString) }

    val result = (for {
       (lat, lng) <- OptionT(promiseOfLoc)
       places     <- OptionT(Places.buildUrlFor(lat,lng).get())
       weather    <- OptionT(promiseOfWeather)
    } yield (places, weather)).run

    Async {
        result.orTimeout("Timeout!", 2000).map {response =>
            response.fold(
                result => {
                  result.map(
                   some => Ok("Got:\n\nweather:\n" + some._1 + "\n\nplaces:\n" + some._2)
                  ).getOrElse(BadRequest("lat/lng failed probably?"))
                },
                timeout => InternalServerError(timeout)
            )
        }
    }
}

Con OptionT podemos flatMap como si se tratara de un Option, ganando la capacidad de no procesar nada si tenemos un Ninguno.Al final nos quedamos con una Promise[Option[T]] que es muy agradable para esto.Otra forma buena manera de manejar los errores es usar/EtherT con el mismo método.

|@| es un Aplicativo Generador.Se tarda de 2 Opciones, y devolver un Option((Int, Int)) si ambos lados son Some.Si uno o en ambos lados son None, se devuelve una None.

Nota: para que esto funcione se necesita un scalaz Monad[Promise] ejemplo

implicit val PromiseInstance = new Monad[Promise] {
  // override def map[A,B](fa: Promise[A])(f: A => B) = fa.map(f)
  def point[A](a: => A) = Promise.pure(a)
  def bind[A,B](fa: Promise[A])(f: A => Promise[B]) = fa.flatMap(f)
}

También tenga en cuenta que he escrito todo este código en el editor, No podía ser de llaves que faltan.Pero todo el código debe ser más o menos bien, he probado de partes de ella en la repl.

Por favor, siéntase libre de pedir ayuda sobre #scalaz en el irc, o en el scalaz de grupos de google.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top