5 people like it.

Type-safe URL templates for Nancy

The Nancy web framework parses URLs for you, and passes requests under a given URL route and HTTP method to your program. It relies heavily on C# dynamic objects; these don't translate well in F# code, and it's easy to make mistakes that only show up at run time. Here we define one F# record type for each route, with an attribute that defines the URL, with placeholders for each field in the record. These types implement one generic interface for each HTTP method they support: for GET, PUT and POST, these generic interfaces also specify the types of the HTTP request and response bodies.

Nancy extensions

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
#nowarn "40"
#nowarn "42"
namespace Tim.Nancy.Generic

open System
open System.Collections.Generic
open System.IO
open System.Text
open System.Web
open Microsoft.FSharp.Reflection
open Nancy
open Nancy.ModelBinding
open Tavis.UriTemplates

type IRestResource =
    interface end

type IRestGet<'Response> =
    inherit IRestResource

type IRestPut<'Request, 'Response> =
    inherit IRestResource

type IRestPost<'Request, 'Response> =
    inherit IRestResource

type IRestDelete =
    inherit IRestResource

[<MeasureAnnotatedAbbreviation>]
type string<'Measure> = string

[<AttributeUsage(AttributeTargets.Class, AllowMultiple = true)>]
type UrlAttribute(template  : string) =
    inherit Attribute()

    member t.Template = template

[<AutoOpen>]
module NancyModuleExtensions =

    let private memoize (fn : 'a -> 'b) : 'a -> 'b =
        let cache = Dictionary()
        let syncRoot = obj()
        fun a ->
            lock syncRoot <| fun () ->
                match cache.TryGetValue(a) with
                | true, b -> b
                | false, _ ->
                    let b = fn a
                    cache.[a] <- b
                    b

    let rec private convert : Type -> string -> obj =
        memoize <| fun toType ->
            if toType.IsGenericType && toType.GetGenericTypeDefinition() = typedefof<option<_>> then
                let someCase, convertInner =
                    FSharpType.GetUnionCases(toType)
                    |> Array.pick (fun c ->
                        match c.GetFields() with
                        | [| f |] -> Some (c, convert f.PropertyType)
                        | _ -> None)

                let ctor = FSharpValue.PreComputeUnionConstructor(someCase)
                function
                | null | "" -> null
                | s -> ctor [| convertInner s |]

            elif typeof<IConvertible>.IsAssignableFrom(toType) then
                fun s -> Convert.ChangeType(s, toType)

            else
                failwithf "Can't convert string to %O" toType
            

    [<Sealed>]
    type private RestResourceImpl<'Resource> private () =
        static let typ = typeof<'Resource>

        static let fields, ctor, reader =
            if FSharpType.IsUnion(typ) then
                match FSharpType.GetUnionCases(typ) with
                | [| c |] when c.GetFields() = [| |] ->
                    let value = FSharpValue.MakeUnion(c, [| |])
                    [| |], (fun _ -> value), (fun _ -> [| |])
                | a -> failwithf "Unions must only have one case. %O has %d cases." typ a.Length

            elif FSharpType.IsRecord(typ) then
                [| for pi in FSharpType.GetRecordFields(typ) -> pi.Name, convert pi.PropertyType |],
                    FSharpValue.PreComputeRecordConstructor(typ),
                    FSharpValue.PreComputeRecordReader(typ)

            else
                failwithf "Only single-case unions and records are supported, not %O" typ

        static let urls =
            match typ.GetCustomAttributes(typeof<UrlAttribute>, true) with
            | [| |] -> failwithf "No [<Url>] attribute on %O" typeof<'Resource>
            | a -> [| for attr in a -> (unbox<UrlAttribute> attr).Template |]

        static member Urls = urls

        static member PartsToResource (part : string -> string) : 'Resource =
            let values = Array.map (fun (name, convert) -> convert (part name)) fields
            unbox (ctor values)

        static member ResourceToString (resource : 'Resource) : string =
            let values = reader resource
            let template = UriTemplate(urls.[0])
            
            for name in template.GetParameterNames() do
                let value =
                    match Array.tryFindIndex (fst >> (=) name) fields with
                    | Some n -> values.[n]
                    | None -> failwithf "No field called '%s' in %O" name typeof<'Resource>

                template.SetParameter(name, value)

            template.Resolve()

    let private addRoute<'Resource, 'Response when 'Resource :> IRestResource> (t : NancyModule) (builder : NancyModule.RouteBuilder) (fn : 'Resource -> 'Response) (url : string) =
        let path, queryParams =
            let template = UriTemplate(url)
            for name in template.GetParameterNames() do
                template.SetParameter(name, "{" + name + "}")
                
            match template.Resolve().Replace("%7B", "{").Replace("%7D", "}").Split([| '?' |], 2) with
            | [| |] -> "", Set.empty
            | [| path |] -> path, Set.empty
            | a -> a.[0], Set.ofSeq (HttpUtility.ParseQueryString(a.[1])).AllKeys

        builder.[path] <- fun dict ->
            let dict : DynamicDictionary = unbox dict
            let query : DynamicDictionary = unbox t.Request.Query

            let resource =
                RestResourceImpl<_>.PartsToResource <| fun name ->
                    let dict =
                        if Set.contains name queryParams then
                            query
                        else
                            dict

                    unbox (dict.[name] :?> DynamicDictionaryValue).Value

            box (fn resource)

    [<NoDynamicInvocation>]
    let inline private retype (x : 'a) : 'b = (# "" x : 'b #)

    type NancyModule with
        member t.UrlFor (resource : 'Resource) : string<'Resource> =
            retype (t.ModulePath + RestResourceImpl<_>.ResourceToString(resource))

        member t.GetT<'Resource, 'Response when 'Resource :> IRestGet<'Response>> (fn : 'Resource -> 'Response) =
            Array.iter (addRoute t t.Get fn) RestResourceImpl<'Resource>.Urls

        member t.PutT<'Resource, 'Request, 'Response when 'Resource :> IRestPut<'Request, 'Response>> (fn : 'Resource -> 'Request -> 'Response) =
            Array.iter (addRoute t t.Put (fun resource -> fn resource (t.Bind<_>()))) RestResourceImpl<'Resource>.Urls

        member t.PostT<'Resource, 'Request, 'Response when 'Resource :> IRestPost<'Request, 'Response>> (fn : 'Resource -> 'Request -> 'Response) =
            Array.iter (addRoute t t.Post (fun resource -> fn resource (t.Bind<_>()))) RestResourceImpl<'Resource>.Urls

        member t.DeleteT<'Resource when 'Resource :> IRestDelete> (fn : 'Resource -> unit) =
            Array.iter (addRoute t t.Delete fn) RestResourceImpl<'Resource>.Urls

Demo

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
open System
open System.Text
open Nancy
open Nancy.Hosting.Self
open Nancy.ModelBinding

[<Url("/hello/{Who}")>]
type Hello = { Who : string }
    with interface IRestGet<string>
         interface IRestPut<string, unit>
         interface IRestDelete

[<Url("/hello{?count}")>]
type Hellos = { Count : int option }
    with interface IRestGet<string<Hello> array>

type DemoModule() as t =
    inherit NancyModule()
    static let mutable greetings = Map.empty

    do
        t.GetT <| fun (hellos : Hellos) ->
            let gs = Option.fold (fun gs count -> Seq.truncate count gs) (Map.toSeq greetings) hellos.Count
            [| for who, _ in gs -> t.UrlFor { Who = who } |]

        t.GetT <| fun (hello : Hello) ->
            let greeting = defaultArg (Map.tryFind hello.Who greetings) "Hello"
            sprintf "%s, %s!" greeting hello.Who

        t.PutT <| fun (hello : Hello) (greeting : string) ->
            greetings <- Map.add hello.Who greeting greetings

        t.DeleteT <| fun (hello : Hello) ->
            greetings <- Map.remove hello.Who greetings

type StringModelBinder() =
    interface IModelBinder with
        member t.CanBind typ =
            typ = typeof<string>

        member t.Bind(context, modelType, instance, config, blacklist) =
            let bytes = Array.zeroCreate (int context.Request.Headers.ContentLength)
            let length = context.Request.Body.Read(bytes, 0, bytes.Length)
            box (Encoding.UTF8.GetString(bytes, 0, length))

module Program =

    [<EntryPoint>]
    let main _ =
        let nancyHost = NancyHost(Uri("http://localhost:8888/nancy/"))
        nancyHost.Start()
        printfn "Nancy now listening at http://localhost:8888/nancy/. Press Enter to stop."
        ignore (Console.ReadLine())
        nancyHost.Stop()
        0
namespace Nancy
namespace System
namespace System.Collections
namespace System.Collections.Generic
namespace System.IO
namespace System.Text
namespace System.Web
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Reflection
namespace Nancy.ModelBinding
namespace Tavis
namespace Tavis.UriTemplates
type IRestResource

Full name: Tim.Nancy.Generic.IRestResource
type IRestGet<'Response> =
  interface
    inherit IRestResource
  end

Full name: Tim.Nancy.Generic.IRestGet<_>
Multiple items
type Response =
  new : unit -> Response
  member AddCookie : nancyCookie:INancyCookie -> Response + 3 overloads
  member ContentType : string with get, set
  member Contents : Action<Stream> with get, set
  member Cookies : IList<INancyCookie> with get, set
  member Dispose : unit -> unit
  member Headers : IDictionary<string, string> with get, set
  member PreExecute : context:NancyContext -> Task
  member ReasonPhrase : string with get, set
  member StatusCode : HttpStatusCode with get, set
  ...

Full name: Nancy.Response

--------------------
Response() : unit
type IRestPut<'Request,'Response> =
  interface
    inherit IRestResource
  end

Full name: Tim.Nancy.Generic.IRestPut<_,_>
Multiple items
type Request =
  new : method:string * path:string * scheme:string -> Request + 1 overload
  member Body : RequestStream with get, set
  member ClientCertificate : X509Certificate with get, set
  member Cookies : IDictionary<string, string>
  member Dispose : unit -> unit
  member Files : IEnumerable<HttpFile>
  member Form : obj
  member Headers : RequestHeaders with get, set
  member Method : string with get, set
  member Path : string
  ...

Full name: Nancy.Request

--------------------
Request(method: string, path: string, scheme: string) : unit
Request(method: string, url: Url, ?body: IO.RequestStream, ?headers: IDictionary<string,IEnumerable<string>>, ?ip: string, ?certificate: byte [], ?protocolVersion: string) : unit
type IRestPost<'Request,'Response> =
  interface
    inherit IRestResource
  end

Full name: Tim.Nancy.Generic.IRestPost<_,_>
type IRestDelete =
  interface
    inherit IRestResource
  end

Full name: Tim.Nancy.Generic.IRestDelete
Multiple items
type MeasureAnnotatedAbbreviationAttribute =
  inherit Attribute
  new : unit -> MeasureAnnotatedAbbreviationAttribute

Full name: Microsoft.FSharp.Core.MeasureAnnotatedAbbreviationAttribute

--------------------
new : unit -> MeasureAnnotatedAbbreviationAttribute
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string

--------------------
type string<'Measure> = string

Full name: Tim.Nancy.Generic.string<_>
Multiple items
type MeasureAttribute =
  inherit Attribute
  new : unit -> MeasureAttribute

Full name: Microsoft.FSharp.Core.MeasureAttribute

--------------------
new : unit -> MeasureAttribute
Multiple items
type AttributeUsageAttribute =
  inherit Attribute
  new : validOn:AttributeTargets -> AttributeUsageAttribute
  member AllowMultiple : bool with get, set
  member Inherited : bool with get, set
  member ValidOn : AttributeTargets

Full name: System.AttributeUsageAttribute

--------------------
AttributeUsageAttribute(validOn: AttributeTargets) : unit
type AttributeTargets =
  | Assembly = 1
  | Module = 2
  | Class = 4
  | Struct = 8
  | Enum = 16
  | Constructor = 32
  | Method = 64
  | Property = 128
  | Field = 256
  | Event = 512
  ...

Full name: System.AttributeTargets
field AttributeTargets.Class = 4
Multiple items
type UrlAttribute =
  inherit Attribute
  new : template:string -> UrlAttribute
  member Template : string

Full name: Tim.Nancy.Generic.UrlAttribute

--------------------
new : template:string -> UrlAttribute
val template : string
Multiple items
type Attribute =
  member Equals : obj:obj -> bool
  member GetHashCode : unit -> int
  member IsDefaultAttribute : unit -> bool
  member Match : obj:obj -> bool
  member TypeId : obj
  static member GetCustomAttribute : element:MemberInfo * attributeType:Type -> Attribute + 7 overloads
  static member GetCustomAttributes : element:MemberInfo -> Attribute[] + 15 overloads
  static member IsDefined : element:MemberInfo * attributeType:Type -> bool + 7 overloads

Full name: System.Attribute

--------------------
Attribute() : unit
val t : UrlAttribute
member UrlAttribute.Template : string

Full name: Tim.Nancy.Generic.UrlAttribute.Template
Multiple items
type AutoOpenAttribute =
  inherit Attribute
  new : unit -> AutoOpenAttribute
  new : path:string -> AutoOpenAttribute
  member Path : string

Full name: Microsoft.FSharp.Core.AutoOpenAttribute

--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
val private memoize : fn:('a -> 'b) -> ('a -> 'b) (requires equality)

Full name: Tim.Nancy.Generic.NancyModuleExtensions.memoize
val fn : ('a -> 'b) (requires equality)
val cache : Dictionary<'a,'b> (requires equality)
Multiple items
type Dictionary<'TKey,'TValue> =
  new : unit -> Dictionary<'TKey, 'TValue> + 5 overloads
  member Add : key:'TKey * value:'TValue -> unit
  member Clear : unit -> unit
  member Comparer : IEqualityComparer<'TKey>
  member ContainsKey : key:'TKey -> bool
  member ContainsValue : value:'TValue -> bool
  member Count : int
  member GetEnumerator : unit -> Enumerator<'TKey, 'TValue>
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Item : 'TKey -> 'TValue with get, set
  ...
  nested type Enumerator
  nested type KeyCollection
  nested type ValueCollection

Full name: System.Collections.Generic.Dictionary<_,_>

--------------------
Dictionary() : unit
Dictionary(capacity: int) : unit
Dictionary(comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>) : unit
Dictionary(capacity: int, comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>, comparer: IEqualityComparer<'TKey>) : unit
val syncRoot : Object
type obj = Object

Full name: Microsoft.FSharp.Core.obj
val a : 'a (requires equality)
val lock : lockObject:'Lock -> action:(unit -> 'T) -> 'T (requires reference type)

Full name: Microsoft.FSharp.Core.Operators.lock
Dictionary.TryGetValue(key: 'a, value: byref<'b>) : bool
val b : 'b
val private convert : (Type -> string -> obj)

Full name: Tim.Nancy.Generic.NancyModuleExtensions.convert
type Type =
  inherit MemberInfo
  member Assembly : Assembly
  member AssemblyQualifiedName : string
  member Attributes : TypeAttributes
  member BaseType : Type
  member ContainsGenericParameters : bool
  member DeclaringMethod : MethodBase
  member DeclaringType : Type
  member Equals : o:obj -> bool + 1 overload
  member FindInterfaces : filter:TypeFilter * filterCriteria:obj -> Type[]
  member FindMembers : memberType:MemberTypes * bindingAttr:BindingFlags * filter:MemberFilter * filterCriteria:obj -> MemberInfo[]
  ...

Full name: System.Type
val toType : Type
property Type.IsGenericType: bool
Type.GetGenericTypeDefinition() : Type
val typedefof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typedefof
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
val someCase : UnionCaseInfo
val convertInner : (string -> obj)
type FSharpType =
  static member GetExceptionFields : exceptionType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetFunctionElements : functionType:Type -> Type * Type
  static member GetRecordFields : recordType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetTupleElements : tupleType:Type -> Type []
  static member GetUnionCases : unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo []
  static member IsExceptionRepresentation : exceptionType:Type * ?bindingFlags:BindingFlags -> bool
  static member IsFunction : typ:Type -> bool
  static member IsModule : typ:Type -> bool
  static member IsRecord : typ:Type * ?bindingFlags:BindingFlags -> bool
  static member IsTuple : typ:Type -> bool
  ...

Full name: Microsoft.FSharp.Reflection.FSharpType
static member FSharpType.GetUnionCases : unionType:Type * ?allowAccessToPrivateRepresentation:bool -> UnionCaseInfo []
static member FSharpType.GetUnionCases : unionType:Type * ?bindingFlags:Reflection.BindingFlags -> UnionCaseInfo []
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val pick : chooser:('T -> 'U option) -> array:'T [] -> 'U

Full name: Microsoft.FSharp.Collections.Array.pick
val c : UnionCaseInfo
member UnionCaseInfo.GetFields : unit -> Reflection.PropertyInfo []
val f : Reflection.PropertyInfo
union case Option.Some: Value: 'T -> Option<'T>
property Reflection.PropertyInfo.PropertyType: Type
union case Option.None: Option<'T>
val ctor : (obj [] -> obj)
type FSharpValue =
  static member GetExceptionFields : exn:obj * ?bindingFlags:BindingFlags -> obj []
  static member GetRecordField : record:obj * info:PropertyInfo -> obj
  static member GetRecordFields : record:obj * ?bindingFlags:BindingFlags -> obj []
  static member GetTupleField : tuple:obj * index:int -> obj
  static member GetTupleFields : tuple:obj -> obj []
  static member GetUnionFields : value:obj * unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo * obj []
  static member MakeFunction : functionType:Type * implementation:(obj -> obj) -> obj
  static member MakeRecord : recordType:Type * values:obj [] * ?bindingFlags:BindingFlags -> obj
  static member MakeTuple : tupleElements:obj [] * tupleType:Type -> obj
  static member MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?bindingFlags:BindingFlags -> obj
  ...

Full name: Microsoft.FSharp.Reflection.FSharpValue
static member FSharpValue.PreComputeUnionConstructor : unionCase:UnionCaseInfo * ?allowAccessToPrivateRepresentation:bool -> (obj [] -> obj)
static member FSharpValue.PreComputeUnionConstructor : unionCase:UnionCaseInfo * ?bindingFlags:Reflection.BindingFlags -> (obj [] -> obj)
val s : string
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
type IConvertible =
  member GetTypeCode : unit -> TypeCode
  member ToBoolean : provider:IFormatProvider -> bool
  member ToByte : provider:IFormatProvider -> byte
  member ToChar : provider:IFormatProvider -> char
  member ToDateTime : provider:IFormatProvider -> DateTime
  member ToDecimal : provider:IFormatProvider -> decimal
  member ToDouble : provider:IFormatProvider -> float
  member ToInt16 : provider:IFormatProvider -> int16
  member ToInt32 : provider:IFormatProvider -> int
  member ToInt64 : provider:IFormatProvider -> int64
  ...

Full name: System.IConvertible
type Convert =
  static val DBNull : obj
  static member ChangeType : value:obj * typeCode:TypeCode -> obj + 3 overloads
  static member FromBase64CharArray : inArray:char[] * offset:int * length:int -> byte[]
  static member FromBase64String : s:string -> byte[]
  static member GetTypeCode : value:obj -> TypeCode
  static member IsDBNull : value:obj -> bool
  static member ToBase64CharArray : inArray:byte[] * offsetIn:int * length:int * outArray:char[] * offsetOut:int -> int + 1 overload
  static member ToBase64String : inArray:byte[] -> string + 3 overloads
  static member ToBoolean : value:obj -> bool + 17 overloads
  static member ToByte : value:obj -> byte + 18 overloads
  ...

Full name: System.Convert
Convert.ChangeType(value: obj, conversionType: Type) : obj
Convert.ChangeType(value: obj, typeCode: TypeCode) : obj
Convert.ChangeType(value: obj, conversionType: Type, provider: IFormatProvider) : obj
Convert.ChangeType(value: obj, typeCode: TypeCode, provider: IFormatProvider) : obj
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
Multiple items
type SealedAttribute =
  inherit Attribute
  new : unit -> SealedAttribute
  new : value:bool -> SealedAttribute
  member Value : bool

Full name: Microsoft.FSharp.Core.SealedAttribute

--------------------
new : unit -> SealedAttribute
new : value:bool -> SealedAttribute
Multiple items
type private RestResourceImpl<'Resource> =
  new : unit -> RestResourceImpl<'Resource>
  static member PartsToResource : part:(string -> string) -> 'Resource
  static member ResourceToString : resource:'Resource -> string
  static member Urls : string []

Full name: Tim.Nancy.Generic.NancyModuleExtensions.RestResourceImpl<_>

--------------------
private new : unit -> RestResourceImpl<'Resource>
val typ : Type
val fields : (string * (string -> obj)) []
val reader : (obj -> obj [])
static member FSharpType.IsUnion : typ:Type * ?allowAccessToPrivateRepresentation:bool -> bool
static member FSharpType.IsUnion : typ:Type * ?bindingFlags:Reflection.BindingFlags -> bool
val value : obj
static member FSharpValue.MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?allowAccessToPrivateRepresentation:bool -> obj
static member FSharpValue.MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?bindingFlags:Reflection.BindingFlags -> obj
val a : UnionCaseInfo []
property Array.Length: int
static member FSharpType.IsRecord : typ:Type * ?allowAccessToPrivateRepresentation:bool -> bool
static member FSharpType.IsRecord : typ:Type * ?bindingFlags:Reflection.BindingFlags -> bool
val pi : Reflection.PropertyInfo
static member FSharpType.GetRecordFields : recordType:Type * ?allowAccessToPrivateRepresentation:bool -> Reflection.PropertyInfo []
static member FSharpType.GetRecordFields : recordType:Type * ?bindingFlags:Reflection.BindingFlags -> Reflection.PropertyInfo []
property Reflection.MemberInfo.Name: string
static member FSharpValue.PreComputeRecordConstructor : recordType:Type * ?allowAccessToPrivateRepresentation:bool -> (obj [] -> obj)
static member FSharpValue.PreComputeRecordConstructor : recordType:Type * ?bindingFlags:Reflection.BindingFlags -> (obj [] -> obj)
static member FSharpValue.PreComputeRecordReader : recordType:Type * ?allowAccessToPrivateRepresentation:bool -> (obj -> obj [])
static member FSharpValue.PreComputeRecordReader : recordType:Type * ?bindingFlags:Reflection.BindingFlags -> (obj -> obj [])
val urls : string []
Reflection.MemberInfo.GetCustomAttributes(inherit: bool) : obj []
Reflection.MemberInfo.GetCustomAttributes(attributeType: Type, inherit: bool) : obj []
val a : obj []
val attr : obj
val unbox : value:obj -> 'T

Full name: Microsoft.FSharp.Core.Operators.unbox
static member private RestResourceImpl.Urls : string []

Full name: Tim.Nancy.Generic.NancyModuleExtensions.RestResourceImpl`1.Urls
static member private RestResourceImpl.PartsToResource : part:(string -> string) -> 'Resource

Full name: Tim.Nancy.Generic.NancyModuleExtensions.RestResourceImpl`1.PartsToResource
val part : (string -> string)
val values : obj []
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val name : string
val convert : (string -> obj)
static member private RestResourceImpl.ResourceToString : resource:'Resource -> string

Full name: Tim.Nancy.Generic.NancyModuleExtensions.RestResourceImpl`1.ResourceToString
val resource : 'Resource
val template : UriTemplate
Multiple items
type UriTemplate =
  new : template:string * ?resolvePartially:bool * ?caseInsensitiveParameterNames:bool -> UriTemplate
  member ClearParameter : name:string -> unit
  member GetParameterNames : unit -> IEnumerable<string>
  member Resolve : unit -> string
  member SetParameter : name:string * value:obj -> unit + 3 overloads
  member ToString : unit -> string

Full name: Tavis.UriTemplates.UriTemplate

--------------------
UriTemplate(template: string, ?resolvePartially: bool, ?caseInsensitiveParameterNames: bool) : unit
UriTemplate.GetParameterNames() : IEnumerable<string>
val tryFindIndex : predicate:('T -> bool) -> array:'T [] -> int option

Full name: Microsoft.FSharp.Collections.Array.tryFindIndex
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val n : int
UriTemplate.SetParameter(name: string, value: IDictionary<string,string>) : unit
UriTemplate.SetParameter(name: string, value: IEnumerable<string>) : unit
UriTemplate.SetParameter(name: string, value: string) : unit
UriTemplate.SetParameter(name: string, value: obj) : unit
UriTemplate.Resolve() : string
val private addRoute : t:NancyModule -> builder:NancyModule.RouteBuilder -> fn:(#IRestResource -> 'Response) -> url:string -> unit

Full name: Tim.Nancy.Generic.NancyModuleExtensions.addRoute
val t : NancyModule
type NancyModule =
  member After : AfterPipeline with get, set
  member Before : BeforePipeline with get, set
  member Context : NancyContext with get, set
  member Delete : RouteBuilder
  member Get : RouteBuilder
  member Head : RouteBuilder
  member ModelBinderLocator : IModelBinderLocator with get, set
  member ModelValidationResult : ModelValidationResult with get, set
  member ModulePath : string with get, set
  member Negotiate : Negotiator
  ...
  nested type RouteBuilder

Full name: Nancy.NancyModule
val builder : NancyModule.RouteBuilder
type RouteBuilder =
  new : method:string * parentModule:NancyModule -> RouteBuilder
  member Item : string -> Func<obj, obj> with set
  member Item : string * Func<NancyContext, bool> -> Func<obj, obj> with set
  member Item : string * bool -> Func<obj, CancellationToken, Task<obj>> with set
  member Item : string * string -> Func<obj, obj> with set
  member Item : string * Func<NancyContext, bool> * bool -> Func<obj, CancellationToken, Task<obj>> with set
  member Item : string * string * Func<NancyContext, bool> -> Func<obj, obj> with set
  member Item : string * string * bool -> Func<obj, CancellationToken, Task<obj>> with set
  member Item : string * string * Func<NancyContext, bool> * bool -> Func<obj, CancellationToken, Task<obj>> with set

Full name: Nancy.NancyModule.RouteBuilder
val fn : (#IRestResource -> 'Response)
val url : string
val path : string
val queryParams : Set<string>
Multiple items
module Set

from Microsoft.FSharp.Collections

--------------------
type Set<'T (requires comparison)> =
  interface IComparable
  interface IEnumerable
  interface IEnumerable<'T>
  interface ICollection<'T>
  new : elements:seq<'T> -> Set<'T>
  member Add : value:'T -> Set<'T>
  member Contains : value:'T -> bool
  override Equals : obj -> bool
  member IsProperSubsetOf : otherSet:Set<'T> -> bool
  member IsProperSupersetOf : otherSet:Set<'T> -> bool
  ...

Full name: Microsoft.FSharp.Collections.Set<_>

--------------------
new : elements:seq<'T> -> Set<'T>
val empty<'T (requires comparison)> : Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.empty
val a : string []
val ofSeq : elements:seq<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.ofSeq
Multiple items
type HttpUtility =
  new : unit -> HttpUtility
  static member HtmlAttributeEncode : s:string -> string + 1 overload
  static member HtmlDecode : s:string -> string + 1 overload
  static member HtmlEncode : s:string -> string + 2 overloads
  static member JavaScriptStringEncode : value:string -> string + 1 overload
  static member ParseQueryString : query:string -> NameValueCollection + 1 overload
  static member UrlDecode : str:string -> string + 3 overloads
  static member UrlDecodeToBytes : str:string -> byte[] + 3 overloads
  static member UrlEncode : str:string -> string + 3 overloads
  static member UrlEncodeToBytes : str:string -> byte[] + 3 overloads
  ...

Full name: System.Web.HttpUtility

--------------------
HttpUtility() : unit
HttpUtility.ParseQueryString(query: string) : Collections.Specialized.NameValueCollection
HttpUtility.ParseQueryString(query: string, encoding: Encoding) : Collections.Specialized.NameValueCollection
val dict : obj
val dict : DynamicDictionary
Multiple items
type DynamicDictionary =
  inherit DynamicObject
  new : unit -> DynamicDictionary
  member Add : item:KeyValuePair<string, obj> -> unit + 1 overload
  member Clear : unit -> unit
  member Contains : item:KeyValuePair<string, obj> -> bool
  member ContainsKey : key:string -> bool
  member CopyTo : array:KeyValuePair<string, obj>[] * arrayIndex:int -> unit
  member Count : int
  member Equals : other:DynamicDictionary -> bool + 1 overload
  member GetDynamicMemberNames : unit -> IEnumerable<string>
  member GetEnumerator : unit -> IEnumerator<string>
  ...

Full name: Nancy.DynamicDictionary

--------------------
DynamicDictionary() : unit
val query : DynamicDictionary
property NancyModule.Request: Request
property Request.Query: obj
val resource : #IRestResource
type private RestResourceImpl<'Resource> =
  new : unit -> RestResourceImpl<'Resource>
  static member PartsToResource : part:(string -> string) -> 'Resource
  static member ResourceToString : resource:'Resource -> string
  static member Urls : string []

Full name: Tim.Nancy.Generic.NancyModuleExtensions.RestResourceImpl<_>
val contains : element:'T -> set:Set<'T> -> bool (requires comparison)

Full name: Microsoft.FSharp.Collections.Set.contains
Multiple items
type DynamicDictionaryValue =
  inherit DynamicObject
  new : value:obj -> DynamicDictionaryValue
  member Default<'T> : ?defaultValue:'T -> 'T
  member Equals : compareValue:DynamicDictionaryValue -> bool + 1 overload
  member GetHashCode : unit -> int
  member GetTypeCode : unit -> TypeCode
  member HasValue : bool
  member ToBoolean : provider:IFormatProvider -> bool
  member ToByte : provider:IFormatProvider -> byte
  member ToChar : provider:IFormatProvider -> char
  member ToDateTime : provider:IFormatProvider -> DateTime
  ...

Full name: Nancy.DynamicDictionaryValue

--------------------
DynamicDictionaryValue(value: obj) : unit
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
Multiple items
type NoDynamicInvocationAttribute =
  inherit Attribute
  new : unit -> NoDynamicInvocationAttribute

Full name: Microsoft.FSharp.Core.NoDynamicInvocationAttribute

--------------------
new : unit -> NoDynamicInvocationAttribute
val private retype : x:'a -> 'b

Full name: Tim.Nancy.Generic.NancyModuleExtensions.retype
val x : 'a
member NancyModule.UrlFor : resource:'Resource -> string<'Resource>

Full name: Tim.Nancy.Generic.NancyModuleExtensions.UrlFor
property NancyModule.ModulePath: string
member NancyModule.GetT : fn:(#IRestGet<'Response> -> 'Response) -> unit

Full name: Tim.Nancy.Generic.NancyModuleExtensions.GetT
val fn : (#IRestGet<'Response> -> 'Response)
val iter : action:('T -> unit) -> array:'T [] -> unit

Full name: Microsoft.FSharp.Collections.Array.iter
property NancyModule.Get: NancyModule.RouteBuilder
member NancyModule.PutT : fn:(#IRestPut<'Request,'Response> -> 'Request -> 'Response) -> unit

Full name: Tim.Nancy.Generic.NancyModuleExtensions.PutT
val fn : (#IRestPut<'Request,'Response> -> 'Request -> 'Response)
property NancyModule.Put: NancyModule.RouteBuilder
val resource : #IRestPut<'Request,'Response>
(extension) INancyModule.Bind<'TModel>() : 'TModel
(extension) INancyModule.Bind([<ParamArray>] blacklistedProperties: string []) : obj
(extension) INancyModule.Bind<'TModel>([<ParamArray>] blacklistedProperties: string []) : 'TModel
(extension) INancyModule.Bind<'TModel>([<ParamArray>] blacklistedProperties: Linq.Expressions.Expression<Func<'TModel,obj>> []) : 'TModel
(extension) INancyModule.Bind<'TModel>(configuration: BindingConfig) : 'TModel
(extension) INancyModule.Bind(configuration: BindingConfig, [<ParamArray>] blacklistedProperties: string []) : obj
(extension) INancyModule.Bind<'TModel>(configuration: BindingConfig, [<ParamArray>] blacklistedProperties: string []) : 'TModel
(extension) INancyModule.Bind<'TModel>(configuration: BindingConfig, blacklistedProperty: Linq.Expressions.Expression<Func<'TModel,obj>>) : 'TModel
(extension) INancyModule.Bind<'TModel>(configuration: BindingConfig, [<ParamArray>] blacklistedProperties: Linq.Expressions.Expression<Func<'TModel,obj>> []) : 'TModel
member NancyModule.PostT : fn:(#IRestPost<'Request,'Response> -> 'Request -> 'Response) -> unit

Full name: Tim.Nancy.Generic.NancyModuleExtensions.PostT
val fn : (#IRestPost<'Request,'Response> -> 'Request -> 'Response)
property NancyModule.Post: NancyModule.RouteBuilder
val resource : #IRestPost<'Request,'Response>
member NancyModule.DeleteT : fn:(#IRestDelete -> unit) -> unit

Full name: Tim.Nancy.Generic.NancyModuleExtensions.DeleteT
val fn : (#IRestDelete -> unit)
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
property NancyModule.Delete: NancyModule.RouteBuilder
namespace Nancy.Hosting
namespace Nancy.Hosting.Self
Multiple items
type Url =
  new : unit -> Url + 1 overload
  member BasePath : string with get, set
  member Clone : unit -> Url
  member HostName : string with get, set
  member IsSecure : bool
  member Path : string with get, set
  member Port : Nullable<int> with get, set
  member Query : string with get, set
  member Scheme : string with get, set
  member SiteBase : string
  ...

Full name: Nancy.Url

--------------------
type UrlAttribute =
  inherit Attribute
  new : template:string -> UrlAttribute
  member Template : string

Full name: Tim.Nancy.Generic.UrlAttribute

--------------------
Url() : unit
Url(url: string) : unit

--------------------
new : template:string -> UrlAttribute
type Hello =
  {Who: string;}
  interface IRestDelete
  interface IRestPut<string,unit>
  interface IRestGet<string>

Full name: Tim.Nancy.Generic.Hello
Hello.Who: string
type Hellos =
  {Count: int option;}
  interface IRestGet<string<Hello> array>

Full name: Tim.Nancy.Generic.Hellos
Hellos.Count: int option
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
type 'T array = 'T []

Full name: Microsoft.FSharp.Core.array<_>
Multiple items
type DemoModule =
  inherit NancyModule
  new : unit -> DemoModule

Full name: Tim.Nancy.Generic.DemoModule

--------------------
new : unit -> DemoModule
val t : DemoModule
Multiple items
type NancyModule =
  member After : AfterPipeline with get, set
  member Before : BeforePipeline with get, set
  member Context : NancyContext with get, set
  member Delete : RouteBuilder
  member Get : RouteBuilder
  member Head : RouteBuilder
  member ModelBinderLocator : IModelBinderLocator with get, set
  member ModelValidationResult : ModelValidationResult with get, set
  member ModulePath : string with get, set
  member Negotiate : Negotiator
  ...
  nested type RouteBuilder

Full name: Nancy.NancyModule

--------------------
NancyModule() : unit
NancyModule(modulePath: string) : unit
val mutable greetings : Map<string,string>
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.empty
val hellos : Hellos
val gs : seq<string * string>
module Option

from Microsoft.FSharp.Core
val fold : folder:('State -> 'T -> 'State) -> state:'State -> option:'T option -> 'State

Full name: Microsoft.FSharp.Core.Option.fold
val count : int
module Seq

from Microsoft.FSharp.Collections
val truncate : count:int -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.truncate
val toSeq : table:Map<'Key,'T> -> seq<'Key * 'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.toSeq
val who : string
member NancyModule.UrlFor : resource:'Resource -> string<'Resource>
member NancyModule.GetT : fn:(#IRestGet<'Response> -> 'Response) -> unit
val hello : Hello
val greeting : string
val defaultArg : arg:'T option -> defaultValue:'T -> 'T

Full name: Microsoft.FSharp.Core.Operators.defaultArg
val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.tryFind
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
member NancyModule.PutT : fn:(#IRestPut<'Request,'Response> -> 'Request -> 'Response) -> unit
val add : key:'Key -> value:'T -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.add
member NancyModule.DeleteT : fn:(#IRestDelete -> unit) -> unit
val remove : key:'Key -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.remove
Multiple items
type StringModelBinder =
  interface IModelBinder
  new : unit -> StringModelBinder

Full name: Tim.Nancy.Generic.StringModelBinder

--------------------
new : unit -> StringModelBinder
type IModelBinder =
  member CanBind : modelType:Type -> bool

Full name: Nancy.ModelBinding.IModelBinder
val t : StringModelBinder
override StringModelBinder.CanBind : typ:Type -> bool

Full name: Tim.Nancy.Generic.StringModelBinder.CanBind
override StringModelBinder.Bind : context:NancyContext * modelType:Type * instance:obj * config:BindingConfig * blacklist:string [] -> obj

Full name: Tim.Nancy.Generic.StringModelBinder.Bind
val context : NancyContext
val modelType : Type
val instance : obj
val config : BindingConfig
val blacklist : string []
val bytes : byte []
val zeroCreate : count:int -> 'T []

Full name: Microsoft.FSharp.Collections.Array.zeroCreate
property NancyContext.Request: Request
property Request.Headers: RequestHeaders
property RequestHeaders.ContentLength: int64
val length : int
property Request.Body: IO.RequestStream
IO.RequestStream.Read(buffer: byte [], offset: int, count: int) : int
type Encoding =
  member BodyName : string
  member Clone : unit -> obj
  member CodePage : int
  member DecoderFallback : DecoderFallback with get, set
  member EncoderFallback : EncoderFallback with get, set
  member EncodingName : string
  member Equals : value:obj -> bool
  member GetByteCount : chars:char[] -> int + 3 overloads
  member GetBytes : chars:char[] -> byte[] + 5 overloads
  member GetCharCount : bytes:byte[] -> int + 2 overloads
  ...

Full name: System.Text.Encoding
property Encoding.UTF8: Encoding
Encoding.GetString(bytes: byte []) : string
Encoding.GetString(bytes: byte [], index: int, count: int) : string
module Program

from Tim.Nancy.Generic
Multiple items
type EntryPointAttribute =
  inherit Attribute
  new : unit -> EntryPointAttribute

Full name: Microsoft.FSharp.Core.EntryPointAttribute

--------------------
new : unit -> EntryPointAttribute
val main : string [] -> int

Full name: Tim.Nancy.Generic.Program.main
val nancyHost : NancyHost
Multiple items
type NancyHost =
  new : [<ParamArray>] baseUris:Uri[] -> NancyHost + 5 overloads
  member Dispose : unit -> unit
  member Start : unit -> unit
  member Stop : unit -> unit

Full name: Nancy.Hosting.Self.NancyHost

--------------------
NancyHost([<ParamArray>] baseUris: Uri []) : unit
NancyHost(configuration: HostConfiguration, [<ParamArray>] baseUris: Uri []) : unit
NancyHost(bootstrapper: Bootstrapper.INancyBootstrapper, [<ParamArray>] baseUris: Uri []) : unit
NancyHost(baseUri: Uri, bootstrapper: Bootstrapper.INancyBootstrapper) : unit
NancyHost(bootstrapper: Bootstrapper.INancyBootstrapper, configuration: HostConfiguration, [<ParamArray>] baseUris: Uri []) : unit
NancyHost(baseUri: Uri, bootstrapper: Bootstrapper.INancyBootstrapper, configuration: HostConfiguration) : unit
Multiple items
type Uri =
  new : uriString:string -> Uri + 5 overloads
  member AbsolutePath : string
  member AbsoluteUri : string
  member Authority : string
  member DnsSafeHost : string
  member Equals : comparand:obj -> bool
  member Fragment : string
  member GetComponents : components:UriComponents * format:UriFormat -> string
  member GetHashCode : unit -> int
  member GetLeftPart : part:UriPartial -> string
  ...

Full name: System.Uri

--------------------
Uri(uriString: string) : unit
Uri(uriString: string, uriKind: UriKind) : unit
Uri(baseUri: Uri, relativeUri: string) : unit
Uri(baseUri: Uri, relativeUri: Uri) : unit
NancyHost.Start() : unit
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...

Full name: System.Console
Console.ReadLine() : string
NancyHost.Stop() : unit

More information

Link:http://fssnip.net/gX
Posted:4 years ago
Author:Tim Robinson
Tags: web , nancy