Ever since Microsoft’s first efforts to deliver a REST style framework in .net, back in 3.5, there has been a continuous stream of questions that has asked: how to I add a service reference to that API? How do I generate a client proxy? How do I access the WSDL for the REST service? Can I generate classes from WADL?
For years I have been telling people, that you can’t do that. REST doesn’t work like that. But many developers insist that is what they want, and I believe I understand why they want it. It just feels so friction free.
I may have found a compromise. With the new features in becoming available in ASP.NET Web API and the benefits of a package management system like Nuget (or OpenWrap), I think you can finally get some of the benefits of a RESTful approach whilst keeping things very convenient.
Data as an architectural element
Before I make my pitch, I want to highlight the aspect of REST that we are concerning ourselves with. The REST constraints encourage us to build clients and servers that are very loosely coupled. This allows the client and server to evolve independently and if we do things right we may find that we can use the client to access multiple services and our service could be consumed by multiple different clients.
This decoupling is achieved by focusing on the data that is transferred between the client and server as a first class citizen of the architecture. In the world of RPC, the data that is passed is often simply an attribute of the procedural endpoint rather than a core architectural concern.
The data that is passed between components of a RESTful system are called representations and their contents are described by Internet Media Types. Next time you hear someone tell you that REST doesn’t have contracts, tell them that Internet Media Types are the contracts and there is a public registry of contracts here.
Contracts allow change
But, I hear you say, the IANA registry doesn’t have a registered media type for Girl Scout to-do lists which I need for my app. You are correct and there are reasons for that, that I am going to completely side step for now. So, how will we achieve REST nirvana if we don’t have a standard media type to use.
Let me reveal to you REST’s dirty little secret. REST doesn’t actually reduce coupling between the client and the server at all. It just moves it. It uses computer science’s most powerful weapon, the “layer of indirection”. By allowing the server to be dependent on the media type and the client be dependent on the media type, the client and server can communicate without being directly coupled. This means you can happily deploy new clients and new servers and as long as you follow a few other rules, nothing should break. The only time you need to be careful is when your “media type” changes. Then you need to update both the client and server.
So how can we manage a chunk of code that is shared between the client and the server? This is where Nuget|OpenWrap can come to the rescue. By creating an independent package we can control the versioning of that component, we provide an easy way for people who want to consume our API to get at our data and they can easily update their client when we push updates.
Introducing WebPacks
These days, if an idea is to succeed it needs a cool name, so considering we are still waiting for JetPacks I decided that WebPacks could keep us going in the meanwhile.
Defn: A webpack is binary component that is deployed using a package management system that contains all the data formats that are shared between a Web API and its clients.
In order to build a a WebPack using ASP.NET Web API we need to include two things
- the CLR types that our API wants to share. e.g. Todolist, contact, dog, invoice.
- Media Type formatters that are capable of serializing and de-serializing those types.
I have packaged up a sample WebPack, client and server using the canonical Contact as the shared object and put it here. Feel free to poke around in the code while I tell the rest of the story.
I hear people asking, isn’t this what people normally call a “client library”, or “client SDK”? Not really. The difference is that a WebPack does not contain any information about the resources of the server. It contains no URL information. It does not know what functionality the server API exposes, it only knows the data building blocks of the service. It’s like being provided a dictionary of English words, so that later you can use it to comprehend a written text. The API will use those building blocks to build an application and the glue that holds all the blocks together is the application protocol, HTTP. This is what will allow our server to add and change functionality without breaking clients, because the clients don’t know in advance what the server can do with that data.
Self-description and discovery
One of the beautiful characteristics of RESTful system is that you should be able to follow your nose to discover how things work and what they mean. When a client developer first comes across a link to our API and issues a HTTP GET, there should be information in the response that helps decide what can be done with that information. Or put another way, what contract is that representation adhering too. The rules of HTTP say that the Content Type header in the response should provide the Internet Media Type that defines the contract of the representation body. So, what media type are we going to use?
One option is to go all custom and use
application/vnd.nuget.ContactWebPack+json
I have taken a whole bunch of liberties in defining this media type. I’m supposed to register this media type with IANA before putting it out on the wild web. Using nuget as a vendor name is a little twisted. The other problem with completely custom media types like this is that web browsers don’t have a clue what to do with it. They don’t know that contract so they just offer up the “save as/download” dialog. An alternative would be something like,
application/json;webpack=org.nuget.packages.ContactWebPack
This means that dumb clients like browsers will see it as application/json but our WebPack savvy clients/developers can be aware of which webpack contains the contracts and formatters.
Everything Evolves
Reviewing what we have covered so far, a API developer should create a WebPack with the contracts and formatters that they wish to share. The API developer can then build a service that exposes resources using these contracts defined in the WebPack. Client developers add a reference to the Nuget package, and use the provided formatters to allow the HTTP client library deserialize the representations into CLR objects.
Over time as changes occur to the service, some changes may require updating the webpack but many others will not. For example as an api grows there are often requests to add new filtered collections and relations between objects. These changes require addition resources to be added to the server, but they do not necessarily require changing the WebPack.
So far I have only talked about using WebPacks to store shared types, but they can also be used to share link relations. Using strongly typed link relations can be an effective way of sharing service behaviours. However, that I will explore in a future post.