Como retornar o enumerador de JSON do ReactiveMongo no Play 2
-
21-12-2019 - |
Pergunta
Em nosso projeto estamos usando ReactiveMongo
com Play 2.2.1
.
O problema é que o fluxo de dados em uma forma de Enumerator[A]
, retornado por ReactiveMongo
é na verdade um fluxo de objetos de valor, que não são separados por vírgulas e não possuem anotações de início e fim de fluxo, que podem ser tratadas como instruções de abertura e fechamento de array.
Isto cria um problema para JSON
consumidor JS client
, já que o formato esperado é[A1,A2, ...]
Então saltámos e transformamos a nossa Enumeratee[A]
para Enumerator[String]
, verificando se é o primeiro elemento ou não:
var first:Boolean = true
val aToStrs = (as.map(a => {
if(first) {
first = false;
Json.stringify(Json.toJson(a))
} else {
"," + Json.stringify(Json.toJson(a))
}
}))
Ok.chunked(
Enumerator.enumInput(Input.El("[")) andThen
aToStrs andThen
Enumerator.enumInput(Input.El("]")) andThen
Enumerator.enumInput(Input.EOF)
)
Isso funciona, mas parece que inventamos a roda.
Existe uma solução melhor para este problema comum?
Solução
Se você usar Comet ou EventSource, não precisará criar manualmente uma maneira de gerar saída e também poderá analisar o item de resposta por item no cliente.Responder com uma matriz forçaria você a escrever seu próprio código de análise ou esperar até que tudo chegasse ao lado do cliente antes de poder usar o analisador build int JSON em seu JavaScript.
Streaming com o protocolo EventSource é muito fácil de jogar, você deve ser capaz de fazer algo como:
implicit val cometEncoder = new Comet.CometMessage[JsValue](_.toString)
Ok.chunked(yourEnumerator &> EventSource()).as(EVENT_STREAM)
E então no html do cliente:
<script type="text/javascript">
var es = new EventSource(jsRouter.controllers.Application.streamIt().url)
es.addEventListener("message", function (event) {
var item = JSON.parse(event.data)
// ... do something with the json value ...
})
</script>
Há um exemplo disso nos projetos de amostra da peça que você também pode querer ver $YOUR_PLAY_DIR/samples/scala/eventsource-clock/