In this page we will get an overview of how you can use Fleece together with Suave.
A minimal integration can be done by
open Suave
open Suave.Http
open Suave.Operators
open System.IO
open System.Text
// Fleece and Json related:
open System.Json
open Fleece.SystemJson
open Fleece.SystemJson.Operators
module BusinessApp=
[<RequireQualifiedAccess>]
module Json =
let inline OK (dataObj) : WebPart=
let str = toJson dataObj |> string
Successful.OK str
>=> Writers.setMimeType "application/json; charset=utf-8"
let inline parseRequestForm (ctx : HttpContext) =
let body = ctx.request.rawForm |> Encoding.UTF8.GetString
parseJson body
In the web API part of your business app you would then do something like the code below:
open BusinessApp
type Person = { Name : string }
with
static member JsonObjCodec =
fun name -> { Name = name }
<!> jreq "name" (Some << fun x -> x.Name)
let personHandler : WebPart =
warbler (fun ctx ->
match Json.parseRequestForm ctx with // instead of using mapJson
| Ok (person:Person)->
Json.OK person
// and ideally we would deal with case when the parsing fails as well
)
module Suave
namespace Suave
module Http
from Suave
module Operators
from Suave
namespace System
namespace System.IO
namespace System.Text
namespace System.Json
namespace Fleece
module SystemJson
from Fleece
module Operators
from Fleece.SystemJson
Multiple items
type RequireQualifiedAccessAttribute =
inherit Attribute
new : unit -> RequireQualifiedAccessAttribute
<summary>This attribute is used to indicate that references to the elements of a module, record or union
type require explicit qualified access.</summary>
<category>Attributes</category>
--------------------
new : unit -> RequireQualifiedAccessAttribute
Multiple items
module Json
from Suave.BusinessApp
--------------------
namespace System.Text.Json
--------------------
module Json
from Suave
val OK : dataObj:'a -> WebPart (requires member ToJson)
val dataObj : 'a (requires member ToJson)
Multiple items
module WebPart
from Suave
--------------------
type WebPart = WebPart<HttpContext>
--------------------
type WebPart<'a> = 'a -> Async<'a option>
<summary>
Takes 'a and returns SuaveTask of 'a
SuaveTask is also known as AsyncOption
</summary>
val str : string
val toJson : x:'t -> JsonValue (requires member ToJson)
<summary>
Maps a value to Json
</summary>
Multiple items
val string : value:'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>
--------------------
type string = System.String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
module Successful
from Suave
<summary><para>
2xx successful responses
</para><para>
Functions have signature <code>f :: params... -> HttpContext -> Async<unit> option</code>.
</para><para>
Functions from here are 'end routes' in that they don't require you to keep
returning applicatives, but can end up in an async monad/workflow that writes
the data to the client in the end.
</para></summary>
val OK : body:string -> WebPart
<summary><para>
200
</para><para>
Write the string to the body as UTF-8
</para></summary>
<remarks></remarks>
module Writers
from Suave
<summary>
Module that allows changing the output response in different ways.
Functions have signature f :: params... -> HttpContext -> HttpContext.
</summary>
val setMimeType : mimeType:string -> WebPart
<summary><para>
Set the Content-Type header to the mime type given. Remember that it should
include the encoding of your content. So for example, specifying a mimeType
value of 'application/json; charset=utf-8' is strongly recommended (but
replace 'json' with your own MIME type, of course ;))
</para><para></para><para></para></summary>
<remarks></remarks>
val parseRequestForm : ctx:HttpContext -> 'a ParseResult (requires member OfJson)
val ctx : HttpContext
Multiple items
module HttpContext
from Suave.Http
<summary>
A module that provides functions to create a new HttpContext.
</summary>
--------------------
type HttpContext =
{ request: HttpRequest
runtime: HttpRuntime
connection: Connection
userState: Map<string,obj>
response: HttpResult }
member clientIp : trustProxy:bool -> sources:string list -> IPAddress
member clientPort : trustProxy:bool -> sources:string list -> Port
member clientProto : trustProxy:bool -> sources:string list -> string
member clientIpTrustProxy : IPAddress
member clientPortTrustProxy : Port
member clientProtoTrustProxy : string
member isLocal : bool
static member clientIp_ : Property<HttpContext,IPAddress>
static member clientPort_ : Property<HttpContext,Port>
static member clientProto_ : Property<HttpContext,string>
...
<summary>
The HttpContext is the container of the request, runtime, user-state and
response.
</summary>
val body : string
HttpContext.request: HttpRequest
<summary>
The HTTP request being processed
</summary>
HttpRequest.rawForm: byte []
type Encoding =
interface ICloneable
new : unit -> unit + 2 overloads
member Clone : unit -> obj
member Equals : value: obj -> bool
member GetByteCount : chars: nativeptr<char> * count: int -> int + 5 overloads
member GetBytes : chars: nativeptr<char> * charCount: int * bytes: nativeptr<byte> * byteCount: int -> int + 7 overloads
member GetCharCount : bytes: nativeptr<byte> * count: int -> int + 3 overloads
member GetChars : bytes: nativeptr<byte> * byteCount: int * chars: nativeptr<char> * charCount: int -> int + 4 overloads
member GetDecoder : unit -> Decoder
member GetEncoder : unit -> Encoder
...
<summary>Represents a character encoding.</summary>
property Encoding.UTF8: Encoding with get
<summary>Gets an encoding for the UTF-8 format.</summary>
<returns>An encoding for the UTF-8 format.</returns>
(extension) Encoding.GetString(bytes: inref<System.Buffers.ReadOnlySequence<byte>>) : string
Encoding.GetString(bytes: System.ReadOnlySpan<byte>) : string
Encoding.GetString(bytes: byte []) : string
Encoding.GetString(bytes: nativeptr<byte>, byteCount: int) : string
Encoding.GetString(bytes: byte [], index: int, count: int) : string
val parseJson : x:string -> 'a ParseResult (requires member OfJson)
<summary>
Parses a Json Text and maps to a type
</summary>
module BusinessApp
from Suave
Person.Name: string
val name : string
val jreq : name:string -> getter:('T -> 'param option) -> ConcreteCodec<System.Collections.Generic.KeyValuePair<string,JsonValue> list,System.Collections.Generic.KeyValuePair<string,JsonValue> list,'param,'T> (requires member OfJson and member ToJson)
<summary>
Derives a concrete field codec for a required field
</summary>
union case Option.Some: Value: 'T -> Option<'T>
<summary>The representation of "Value of type 'T"</summary>
<param name="Value">The input value.</param>
<returns>An option representing the value.</returns>
val x : Person
val personHandler : WebPart
val warbler : f:('t -> 't -> 'u) -> 't -> 'u
<summary>
Which bird? A Warbler!
Pipe the request through to a bird that can peck at it.
Put another way, using 'warbler' lets you look at the first parameter and
then make a decision about what thing to return (it's most likely a
WebPart you'll be returning). (Remember, WebPart is
HttpContext -> Async<HttpContext option>) where HttpContext is 'a and
Async<_> is 'b.
</summary>
union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>
<summary>
Represents an OK or a Successful result. The code succeeded with a value of 'T.
</summary>
val person : Person
type Person =
{ Name: string }
static member JsonObjCodec : ConcreteCodec<KeyValuePair<string,JsonValue> list,KeyValuePair<string,JsonValue> list,Person,Person>