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.

Demo

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
[<Url("/hello/{Who}")>]
type Hello = { Who : string }
    with interface IRestGet<string>
         interface IRestPut<string, unit>
         interface IRestDelete

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

    do
        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
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
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<_>
type IRestGet<'Response> =
  interface
    inherit IRestResource
  end

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

Full name: Tim.Nancy.Generic.IRestPut<_,_>
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
type IRestDelete =
  interface
    inherit IRestResource
  end

Full name: Tim.Nancy.Generic.IRestDelete
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
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
Next Version Raw view Test code New version

More information

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