How to set a Json response in suave webpart
Asked Answered
C

2

4

i'm begining with Suave and F#. I'm trying to pass a json serialized object in my webpart to get it in my response.

In php i have this

<?php
header('Access-Control-Allow-Credentials:true');
header('Access-Control-Allow-Headers:Content-Type, Accept');
header('Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Origin:*');
?>
{
 "player1Key":"hdegftzj25",
 "gameKey":"aegfhzkfszl74852"
}

and with this i get my json object, then i tried to do the same with Suave and Newtonsoft.Json

type gameCreate= {
    player1Key : string
    gameKey: string
}

let create= { player1Key = "BadBoys2"; gameKey = "zLUGgtrht4456" }

let json = Newtonsoft.Json.JsonConvert.SerializeObject(create)

//OK (acc |> Json.serialize |> Json.format )
let php =
request (fun r ->
    match r.queryParam "playerName" with
    | Choice1Of2 name ->  OK (movies |> Json.serialize(json) |> Json.format(json))
                        //|>  Response.response(Json.toJson(info))
                        //|>  OK
    | Choice2Of2 msg -> BAD_REQUEST msg)

let webPart = 
choose [
path "/" >=> (OK "Home")
path "/elm/api/create.php" >=> php
]

startWebServer defaultConfig webPart

So i can create and serialize a json object but i don't know how to pass it as http response in my web part and with the above code i keep on getting error on my expressions type in my let php

Courlan answered 2/2, 2017 at 22:59 Comment(5)
What error are you getting? I don't know what type Json.format is, or where you got it from, but you need to pass a string to OK.Brittain
Actually, the code you have in your Choice1Of2 case looks very much off, for any sane implementation of Json.serialize/format I can think of.Brittain
And what is movies? That isn't defined anywhere.Extravagancy
sorry i forgot to replace movies by "create". I get Error tye Incompatibility. Expected (string -> WebPart) -> HttpContext -> 'a but get byte [] -> WebPart type 'string -> WebPart' don't correspond to type 'byte []'Courlan
I followed a tutoriel on Suave aspnetmonsters.com/2016/12/2016-12-31-suaveCourlan
B
4

Looks like you've pulled in a few Json serialization libraries too many - you seem to mix bits of Json.NET and Chiron (which is used in the tutorial), to no great effect...

Let's take a step back. Suave comes with its own Json serialization module, so you can get something working just by using that. Here's how it would look:

let php =
    request (fun r ->
        match r.queryParam "playerName" with
        | Choice1Of2 name ->  
            let json : string = 
                create
                // this comes from Suave.Json, gives you a byte array
                |> Json.toJson           
                // converts the byte array into a string
                |> System.Text.Encoding.UTF8.GetString
            OK json
        | Choice2Of2 msg -> BAD_REQUEST msg)

Now, if you want, you can replace the Json.toJson call with either the Newtonsoft Json.NET or Chiron implementation (but hopefully not a mix of the two). As long as the types align, you should be fine.

For Chiron in particular, you're missing the ToJson static member on the type you want to serialize (this is something that your tutorial does mention). Json.NET has a generic serialize function that produces json corresponding to the record schema, so it's a bit easier to use out of the box, but also requires more work to customize the output if needed.

Brittain answered 3/2, 2017 at 12:28 Comment(0)
S
3

If you want to return a HTTP 200 response with JSON and set HTTP headers in Suave, then you can use the Writers.setHeader function:

Writers.setHeader "Access-Control-Allow-Credentials" "true" >=>
Writers.setHeader "Access-Control-Allow-Headers:Content-Type" "Accept" >=>
Writers.setHeader "Access-Control-Allow-Methods" "GET, POST, PUT, DELETE, OPTIONS" >=>
Writers.setHeader "Access-Control-Allow-Origin" "" >=>
Successful.OK (movies |> Json.serialize |> Json.format)

The whole thing is an expression that constructs a WebPart which you can then compose with other web parts using the functions provided by Suave. So if you wanted to pattern match before setting the headers, you'd use something like:

let php = request (fun r ->
  match r.queryParam "playerName" with
  | Choice1Of2 name ->  
      Writers.setHeader "Access-Control-Allow-Credentials" "true" >=>
      Writers.setHeader "Access-Control-Allow-Headers:Content-Type" "Accept" >=>
      Writers.setHeader 
        "Access-Control-Allow-Methods" "GET, POST, PUT, DELETE, OPTIONS" >=>
      Writers.setHeader "Access-Control-Allow-Origin" "" >=>
      Successful.OK (movies |> Json.serialize |> Json.format)
  | Choice2Of2 msg -> BAD_REQUEST msg)

As you are setting the CORS headers, this snippet might also help.

Supernal answered 3/2, 2017 at 12:5 Comment(2)
Yes, now i'm receiving my json data but it's look like this "{\"player1Key\":\"BadBoys2\",\"gameKey\":\"zLUGgtrht4456\"}" and i don't want thoses backslashes. Any ideas?Courlan
Writers.setHeader "Content-Type" "application/json; charset=UTF-8" is a correct header.Bollard

© 2022 - 2024 — McMap. All rights reserved.