Nitpicker corner: Yes, I know about Open Rasta, NancyFX, FubuMVC and all of the other cool frameworks out there. I am not here today to talk about them. I am not interested in talking about them and why they are so much better in this post.
You might be aware that I am doing a lot of stuff at the HTTP level, owing to the fact that both RavenDB and RavenFS are REST based servers.
As such, I had to become intimately familiar with the HTTP spec, how things work at the low level ASP.Net level, etc. I even had to write my own abstractions to be able to run both inside IIS and as a service. Suffice to say, I feel that I have a lot of experience in building HTTP based system. That said, I am also approaching things from a relatively different angle than most people. I am not aiming to build a business application, I am actually building infrastructure servers.
There was a lot of buzz about the ASP.Net Web API, and I took a brief look at the demo, marked it as “nice, need to check it out some day” in my head and moved on. Then I run into a strange problem in RavenFS. RavenFS is a sibling to RavenDB. Whereas RavenDB is a document database, RavenFS is a distributed & replicated file server for (potentially) very large files. (It is currently in beta testing ,and when we are doing giving it all the bells and whistle of a real product, we will show it to the world , it isn’t really important to this post).
What is important is that I run into a problem with RavenFS, and I felt that there was a strong likelihood that I was doing something wrong in the HTTP layer that was causing this. Despite its outward simplicity, HTTP is pretty complex when you get down to business. So I decided to see what would happen if I would replace the HTTP layer for RavenFS with ASP.Net Web API.
That means that I have been using it in anger for the last week, and here is what I think about it so far.
First, it is a beta. That is something that is important to remember, because it means that it isn’t done yet.
Second, I am talking strictly about the server API. I haven’t even touched the client API as of now.
Third, and most important. I am impressed. It is a really clean API, nice interface, well thought out and quite nice to work with.
More than that, I had to do a bunch of stuff that really isn’t trivial. And there are very little docs for it as of now. I was able to do pretty much everything I wanted by just walking the API and figuring things out on my own.
Things that I particularly liked:
- The API guides you to do the right thing. For example, different headers have different meaning, and you can see that when you look at the different headers collections. You have headers that goes in the response, headers that go in the request, headers that goes for the content, and so on. It really guides you properly to using this as you should.
- A lot of the stuff that is usually hard is now pretty easy to do. Multi part responses, for example. Ranged requests, or proper routing.
- I was able to plug in DI for what I was doing in a couple of minutes without really knowing anything about how things work. And I could do that by providing a single delegate, rather than implement a complex interface.
- I provides support for self hosting, which is crucial for doing things like unit testing the server.
- It is Async to the core.
- I really like the ability to return a value, or a task, or a task of a value, or return an HttpResponseMessage which I can customize to my heart content.
Overall, it just makes sense. I get how it works, and it doesn’t seems like I have to fight anything to get things done.
Please note that this is porting a major project to a completely new platform, and doing some really non trivial things in there while doing this.
Things that I didn’t like with it:
Put simply, errors. To be fair, this isn’t a complaint about the standard error handling, this works just fine. The issue is with infrastructure errors.
For example, if you try to push a 5MB request to the server, by default the request will just die. No error message, and the status code is 503 (message unavailable). This can be pretty frustrating to try to figure out, because there is nothing to tell you what the problem is. And I didn’t look at the request size at first. It just seemed that some request worked, and some didn’t. Even after that I found that it is the size that mattered, it was hard to figure out where we need to fix that (and the answer to that is different depending on where you are running!).
Another example is using PUT or DELETE in your requests. As long as you are running in SelfHost, everything will work just fine. If you switch to IIS, you will get an error (405, Method Not Allowed), again, with no idea how to fix this or why this is happening. This is something that you can fix in the config (sometimes), but it is another error that has horrible usability.
Those are going to be pretty common errors, I am guessing, and any error like that is actually a road block for the users. Having an error code and nothing else thrown at you is really frustrating, and this is something that can really use a good error report. Including details about how to fix the problem.
There are a bunch of other issues that I run into (an NRE when misconfiguring the routing that was really confusing and other stuff like that), but this is beta software, and those are things that will be fixed.
The one thing that I miss as a feature is good support for nested resources (/accounts/1/people/2/notes), which can be a great way to provide additional context for the application. What I actually want to use this for is to be able to do things like: /folders <—FoldersController.Get, Post, Put, Delete and then have: /folders/search <- FolderController.GetSearch., PostSearch, etc.
So I can get the routing by http method even when I am doing controller and action calls.
Final thoughts, RavenFS is now completely working using this model, and I like it. It is really nice API, it works, but most importantly, it makes sense.