Fleece


Giraffe

In this page we will get an overview of how you can use Fleece together with Giraffe.

A minimal integration can be done by looking at how Giraffe implements the method WriteJsonAsync and function json:

open Giraffe
open System.IO
open System.Text
// task computation builder from TaskBuilder.fs:
open FSharp.Control.Tasks.V2.ContextInsensitive
// Fleece and Json related:
open Fleece.SystemJson
open Fleece.SystemJson.Operators

module BusinessApp=
    module Json =
        let inline json (dataObj ) : HttpHandler =
            fun (_ : HttpFunc) (ctx : HttpContext) ->
                ctx.SetContentType "application/json; charset=utf-8"
                toJson dataObj // turn dataObj into Json
                |> string // get the Json string
                |> Encoding.UTF8.GetBytes // turn the string into bytes
                |> ctx.WriteBytesAsync // write bytes to the response

        let inline bindJsonAsync (ctx : HttpContext) =
            task {
                use reader = new StreamReader(ctx.Request.Body)
                let! body = reader.ReadToEndAsync()
                return parseJson body
            }

In the web API part of your business app you would then do something like the code below:

open Giraffe
open FSharp.Control.Tasks.V2.ContextInsensitive
// we open the Json helpers we defined last in order to avoid using the default "json" function from Giraffe:
open BusinessApp.Json
type Person = { Name : string }
with
    static member JsonObjCodec =
        fun name -> { Name = name }
        <!> jreq  "name" (Some << fun x -> x.Name)

let personHandler =
    fun (next : HttpFunc) (ctx : HttpContext) ->
        task {
            match! bindJsonAsync ctx with // instead of using ctx.BindJsonAsync we use the function above
            | Ok (person:Person)->
                return! json person next ctx
            // and ideally we would deal with case when the parsing fails as well
        }

The benefit of doing an integration in this way is:

module Giraffe
namespace System
namespace System.Threading
namespace System.Threading.Tasks
namespace System.IO
Multiple items
type Request = new : unit -> Request member Body : Stream
 fake definition

--------------------
new : unit -> Request
type Stream = inherit MarshalByRefObject interface IAsyncDisposable interface IDisposable new : unit -> unit member BeginRead : buffer: byte [] * offset: int * count: int * callback: AsyncCallback * state: obj -> IAsyncResult member BeginWrite : buffer: byte [] * offset: int * count: int * callback: AsyncCallback * state: obj -> IAsyncResult member Close : unit -> unit member CopyTo : destination: Stream -> unit + 1 overload member CopyToAsync : destination: Stream -> Task + 3 overloads member CreateWaitHandle : unit -> WaitHandle ...
<summary>Provides a generic view of a sequence of bytes. This is an abstract class.</summary>
val failwith : message:string -> 'T
<summary>Throw a <see cref="T:System.Exception" /> exception.</summary>
<param name="message">The exception message.</param>
<returns>The result value.</returns>
Multiple items
type HttpContext = new : unit -> HttpContext member SetContentType : s:string -> 'a member WriteBytesAsync : b:byte array -> Task<HttpContext option> member Request : Request

--------------------
new : unit -> HttpContext
val __ : HttpContext
val s : string
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>
val b : byte array
Multiple items
val byte : value:'T -> byte (requires member op_Explicit)
<summary>Converts the argument to byte. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Byte.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted byte</returns>


--------------------
[<Struct>] type byte = System.Byte
<summary>An abbreviation for the CLI type <see cref="T:System.Byte" />.</summary>
<category>Basic Types</category>


--------------------
type byte<'Measure> = byte
<summary>The type of 8-bit unsigned integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Byte" />.</summary>
<category>Basic Types with Units of Measure</category>
type 'T array = 'T []
<summary>Single dimensional, zero-based arrays, written <c>int[]</c>, <c>string[]</c> etc.</summary>
<remarks>Use the values in the <see cref="T:Microsoft.FSharp.Collections.ArrayModule" /> module to manipulate values of this type, or the notation <c>arr.[x]</c> to get/set array values.</remarks>
<category>Basic Types</category>
Multiple items
type Task = interface IAsyncResult interface IDisposable new : action: Action -> unit + 7 overloads member ConfigureAwait : continueOnCapturedContext: bool -> ConfiguredTaskAwaitable member ContinueWith : continuationAction: Action<Task,obj> * state: obj -> Task + 19 overloads member Dispose : unit -> unit + 1 overload member GetAwaiter : unit -> TaskAwaiter member RunSynchronously : unit -> unit + 1 overload member Start : unit -> unit + 1 overload member Wait : unit -> unit + 4 overloads ...
<summary>Represents an asynchronous operation.</summary>

--------------------
type Task<'TResult> = inherit Task new : function: Func<obj,'TResult> * state: obj -> unit + 7 overloads member ConfigureAwait : continueOnCapturedContext: bool -> ConfiguredTaskAwaitable<'TResult> member ContinueWith : continuationAction: Action<Task<'TResult>,obj> * state: obj -> Task + 19 overloads member GetAwaiter : unit -> TaskAwaiter<'TResult> member Result : 'TResult static member Factory : TaskFactory<'TResult>
<summary>Represents an asynchronous operation that can return a value.</summary>
<typeparam name="TResult">The type of the result produced by this <see cref="T:System.Threading.Tasks.Task`1" />.</typeparam>


--------------------
Task(action: System.Action) : Task
Task(action: System.Action, cancellationToken: System.Threading.CancellationToken) : Task
Task(action: System.Action, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj) : Task
Task(action: System.Action, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj, cancellationToken: System.Threading.CancellationToken) : Task
Task(action: System.Action<obj>, state: obj, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task

--------------------
Task(function: System.Func<'TResult>) : Task<'TResult>
Task(function: System.Func<obj,'TResult>, state: obj) : Task<'TResult>
Task(function: System.Func<'TResult>, cancellationToken: System.Threading.CancellationToken) : Task<'TResult>
Task(function: System.Func<'TResult>, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(function: System.Func<obj,'TResult>, state: obj, cancellationToken: System.Threading.CancellationToken) : Task<'TResult>
Task(function: System.Func<obj,'TResult>, state: obj, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(function: System.Func<'TResult>, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(function: System.Func<obj,'TResult>, state: obj, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
type 'T option = Option<'T>
<summary>The type of optional values. When used from other CLI languages the empty option is the <c>null</c> value. </summary>
<remarks>Use the constructors <c>Some</c> and <c>None</c> to create values of this type. Use the values in the <c>Option</c> module to manipulate values of this type, or pattern match against the values directly. 'None' values will appear as the value <c>null</c> to other CLI languages. Instance methods on this type will appear as static methods to other CLI languages due to the use of <c>null</c> as a value representation.</remarks>
<category index="3">Options</category>
type HttpFuncResult = Task<HttpContext option>
type HttpFunc = HttpContext -> HttpFuncResult
type HttpHandler = HttpFunc -> HttpFunc
module Giraffe from Giraffe
namespace System.Text
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Control

--------------------
namespace Microsoft.FSharp.Control
namespace FSharp.Control.Tasks
module V2 from FSharp.Control.Tasks
module ContextInsensitive from FSharp.Control.Tasks.V2
namespace Fleece
module SystemJson from Fleece
module Operators from Fleece.SystemJson
Multiple items
module Json from Giraffe.BusinessApp

--------------------
namespace System.Text.Json
val json : dataObj:'a -> HttpFunc -> ctx:HttpContext -> HttpFuncResult (requires member ToJson)
val dataObj : 'a (requires member ToJson)
val ctx : HttpContext
member HttpContext.SetContentType : s:string -> 'a
val toJson : x:'t -> System.Json.JsonValue (requires member ToJson)
<summary> Maps a value to Json </summary>
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.GetBytes(chars: inref<System.Buffers.ReadOnlySequence<char>>) : byte []
   (+0 other overloads)
Encoding.GetBytes(s: string) : byte []
   (+0 other overloads)
Encoding.GetBytes(chars: char []) : byte []
   (+0 other overloads)
(extension) Encoding.GetBytes(chars: inref<System.Buffers.ReadOnlySequence<char>>, writer: System.Buffers.IBufferWriter<byte>) : int64
   (+0 other overloads)
(extension) Encoding.GetBytes(chars: inref<System.Buffers.ReadOnlySequence<char>>, bytes: System.Span<byte>) : int
   (+0 other overloads)
(extension) Encoding.GetBytes(chars: System.ReadOnlySpan<char>, writer: System.Buffers.IBufferWriter<byte>) : int64
   (+0 other overloads)
Encoding.GetBytes(chars: System.ReadOnlySpan<char>, bytes: System.Span<byte>) : int
   (+0 other overloads)
Encoding.GetBytes(s: string, index: int, count: int) : byte []
   (+0 other overloads)
Encoding.GetBytes(chars: char [], index: int, count: int) : byte []
   (+0 other overloads)
Encoding.GetBytes(chars: nativeptr<char>, charCount: int, bytes: nativeptr<byte>, byteCount: int) : int
   (+0 other overloads)
member HttpContext.WriteBytesAsync : b:byte array -> System.Threading.Tasks.Task<HttpContext option>
val bindJsonAsync : ctx:HttpContext -> System.Threading.Tasks.Task<'a ParseResult> (requires member OfJson)
val task : FSharp.Control.Tasks.TaskBuilder.TaskBuilderV2
val reader : StreamReader
Multiple items
type StreamReader = inherit TextReader new : stream: Stream -> unit + 10 overloads member Close : unit -> unit member DiscardBufferedData : unit -> unit member Dispose : disposing: bool -> unit member Peek : unit -> int member Read : unit -> int + 2 overloads member ReadAsync : buffer: char [] * index: int * count: int -> Task<int> + 1 overload member ReadBlock : buffer: char [] * index: int * count: int -> int + 1 overload member ReadBlockAsync : buffer: char [] * index: int * count: int -> Task<int> + 1 overload ...
<summary>Implements a <see cref="T:System.IO.TextReader" /> that reads characters from a byte stream in a particular encoding.</summary>

--------------------
StreamReader(stream: Stream) : StreamReader
   (+0 other overloads)
StreamReader(path: string) : StreamReader
   (+0 other overloads)
StreamReader(stream: Stream, detectEncodingFromByteOrderMarks: bool) : StreamReader
   (+0 other overloads)
StreamReader(stream: Stream, encoding: Encoding) : StreamReader
   (+0 other overloads)
StreamReader(path: string, detectEncodingFromByteOrderMarks: bool) : StreamReader
   (+0 other overloads)
StreamReader(path: string, encoding: Encoding) : StreamReader
   (+0 other overloads)
StreamReader(stream: Stream, encoding: Encoding, detectEncodingFromByteOrderMarks: bool) : StreamReader
   (+0 other overloads)
StreamReader(path: string, encoding: Encoding, detectEncodingFromByteOrderMarks: bool) : StreamReader
   (+0 other overloads)
StreamReader(stream: Stream, encoding: Encoding, detectEncodingFromByteOrderMarks: bool, bufferSize: int) : StreamReader
   (+0 other overloads)
StreamReader(path: string, encoding: Encoding, detectEncodingFromByteOrderMarks: bool, bufferSize: int) : StreamReader
   (+0 other overloads)
property HttpContext.Request: Request with get
property Request.Body: Stream with get
val body : string
StreamReader.ReadToEndAsync() : System.Threading.Tasks.Task<string>
val parseJson : x:string -> 'a ParseResult (requires member OfJson)
<summary> Parses a Json Text and maps to a type </summary>
module BusinessApp from Giraffe
module Json from Giraffe.BusinessApp
Person.Name: string
val name : string
val jreq : name:string -> getter:('T -> 'param option) -> ConcreteCodec<System.Collections.Generic.KeyValuePair<string,System.Json.JsonValue> list,System.Collections.Generic.KeyValuePair<string,System.Json.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 : next:HttpFunc -> ctx:HttpContext -> System.Threading.Tasks.Task<HttpContext option>
val next : HttpFunc
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>