Introduction

Up until now we have used the browser to look at our data. In other words Nancy created a view for us and returned html to the client that requested that information. But wouldn’t it be nice if we could use the same for returning html and/or other formats like json or xml. It turns out to be very easy to do with Nancy.

The code can still be found on github.

Content negotiation

This can only work if Nancy is able to change the response based on the request. In other words content negotiation.

According to their wiki.

The content negotiation pipeline will inspect the incoming Accept headers and determine which of the requested media types is the most suitable and format the response accordingly.

The server

For this to work we need to change our Module just a little bit.

Lets take the treesmodule. And change the Get that returns all trees from this

vb.net
1
2
3
4
MyBase.Get("/trees") = Function(parameters)
                                       Return View(New TreesModel() With {.Trees = treeService.AllTrees()})
                                   End Function
            
MyBase.Get("/trees") = Function(parameters)
                                       Return View(New TreesModel() With {.Trees = treeService.AllTrees()})
                                   End Function
            

to this

vb.net
1
2
3
4
MyBase.Get("/trees") = Function(parameters)
                                       Return Negotiate.WithModel(New TreesModel() With {.Trees = treeService.AllTrees()})
                                   End Function
            
MyBase.Get("/trees") = Function(parameters)
                                       Return Negotiate.WithModel(New TreesModel() With {.Trees = treeService.AllTrees()})
                                   End Function
            

Instead of returning a View I now use Negotiate.WithModel and that’s all the changes I made.

Easyhttp client

YOu can now make a newproject and add easyhttp to that and read the list of trees like this.

vb.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Imports System.Net
Imports EasyHttp.Http
 
Module Module1
 
    Sub Main()
        Dim http = New HttpClient()
        http.Request.Accept = HttpContentTypes.ApplicationJson
        Dim trees = http.Get("http://localhost:55360/trees")
        For Each t In trees.DynamicBody.Trees
            Console.WriteLine(t.Id)
            Console.WriteLine(t.Genus)
        Next
        Console.ReadLine()
    End Sub
 
End Module
Imports System.Net
Imports EasyHttp.Http

Module Module1

    Sub Main()
        Dim http = New HttpClient()
        http.Request.Accept = HttpContentTypes.ApplicationJson
        Dim trees = http.Get("http://localhost:55360/trees")
        For Each t In trees.DynamicBody.Trees
            Console.WriteLine(t.Id)
            Console.WriteLine(t.Genus)
        Next
        Console.ReadLine()
    End Sub

End Module

With this as the result.

1
Fagus
2
Quercus
3
Betula

And of course all this time the browser client will just keep on working like nothing happened.

Parameters

We can now also change our second Get in that module to return the data based on the id. To this.

vb.net
1
2
3
4
5
6
7
8
9
10
11
MyBase.Get("/trees/{Id}") = Function(parameters)
                                            Dim result As Integer
                                            Dim isInteger = Integer.TryParse(parameters.id, result)
                                            Dim tree = treeService.FindById(result)
                                            If isInteger AndAlso tree IsNot Nothing Then
                                                Return Negotiate.WithModel(tree)
                                            Else
                                                Return HttpStatusCode.NotFound
                                            End If
                                        End Function
           
MyBase.Get("/trees/{Id}") = Function(parameters)
                                            Dim result As Integer
                                            Dim isInteger = Integer.TryParse(parameters.id, result)
                                            Dim tree = treeService.FindById(result)
                                            If isInteger AndAlso tree IsNot Nothing Then
                                                Return Negotiate.WithModel(tree)
                                            Else
                                                Return HttpStatusCode.NotFound
                                            End If
                                        End Function
           

Again just change the return view call to return Negotiate.WithModel.

Simples.

We can now add an easyhttp call like this.

vb.net
1
2
3
4
        Dim result = http.Get("http://localhost:55360/trees", New With {.Id = 1})
        Dim tree = result.DynamicBody
        Console.WriteLine(tree.Id)
        Console.WriteLine(tree.Genus)
        Dim result = http.Get("http://localhost:55360/trees", New With {.Id = 1})
        Dim tree = result.DynamicBody
        Console.WriteLine(tree.Id)
        Console.WriteLine(tree.Genus)

Sadly that won’t work. Because easyhttp translates that call to http://localhost/trees?id=1 and Nancy wants you to use routes instead. Like this http://localhost/trees/1 . I know how easyhttp does this too, since it was me who added that feature to easyhttp ;-). So I guess I will have to change easyhttp to use it this way.

Anyway if you change your easyhttp call to this

vb.net
1
2
3
4
Dim result = http.Get("http://localhost:55360/trees/1")
        Dim tree = result.DynamicBody
        Console.WriteLine(tree.Id)
        Console.WriteLine(tree.Genus)
Dim result = http.Get("http://localhost:55360/trees/1")
        Dim tree = result.DynamicBody
        Console.WriteLine(tree.Id)
        Console.WriteLine(tree.Genus)

it will work, until I have time to harass Hadi enough so that he does the change or (more likely) until I do the change myself.

Conclusion

It is extremely easy to make Nancy return the response formatted based on the request.