Saturday, 21 April 2012

Web API Governance - Life in a schemaless world (Take 2)

Introduction

[Level C4] While classic web services used WSDL for their schema and description, emerging Web API mainly relies on documentation. This requires human effort and with the rising popularity of Web API it could create problems in maintenance, change management and extension of Web APIs. The solution is automation and this article reviews challenges and possible solutions.

Rise of the Web API


NOTE: This is take 2 of my post, with some updates.

I am very excited at the moment. Microsoft has just released its beta version of its best HTTP implementation to date. ASP.NET Web API has embraced HTTP exposing its full goodness. No more clutter of SOAP-based RPC services. Lean and mean.

So life cannot be any better? Hmmm.. it can! Away from all the hustle and bustle and buzz of the REST APIs (whether they are really RESTful is another discussion which to be frank I am not interested any more), it is important to be objective and almost clinical about the technology. It is important to be able to look back, and see how far we have come so far and yet learn lessons from the past and use the solutions of the previous generation if they are still relevant (in IT terms it is 5-10 years depending on the technology).

There has been a movement in the industry to question the basics. This is good, it weeds out unnecessary abstractions. We have had RDBMS for years now we want NoSQL. We have had XML/SOAP now we want JSON. We have had complex layered server side architecture now we want close to the metal, like node.js or sinatra/nancyfx. Scripting was bad, type safety was good and now scripting is good and everyone wants to escape type safety.

OK, we have had SOAP services and we have never been happy with them. They were clunky, heavy and complex. Now we got Web API which is so much better. But let's have a look at the problems that classic Web Services started tackling and in fact, did a good job in some cases.

Governance in Web Services

This is an SOA term that revolved around managing and organising web services in a consistent fashion. This  would protect the clients as well as allowing the vendors to manage the life of the services. 

Some of the aspects of Governance include:
  1. Contract and description: mainly through WSDL
  2. Registry service and discovery: mainly through UDDI and later WS-Discovery
  3. Versioning
  4. Exception handling
  5. Security and access control: mainly through Web Service Extensions and later WS-Security
To be fair, the work in the area produced some useful technologies and standards. One problem being they are mainly based on the RPC style web services as such not quite useful in the REST style Web API. The issue is problems do still exist and question is whether we do have appropriate tools to address them.

What did we lose on the way?

OK, I am trying to imagine 3 years from now - I am sorry but I see chaos. A good proportion of existing Web Services will be moved to pure HTTP Web APIs. I think it is very likely that the RPC mentality stays with the developers and we end up with RPC style Web APIs. And now what? We are even more vulnerable with no classic Governance safety net.

With classic web services (and WCF), all you needed to point to a web service was its WSDL. It would provide the contract, schemata, faults, security requirements, endpoint addresses and some description. If you would update your service, the WSDL (which it could be generated on the fly) would be updated. In fact in most cases all you needed was the service endpoint address, from where you could get all informations you needed (e.g. by just placing ?wsdl at the end of the address).

We do have some replacements here in HTTP APIs. For example, we do not need SOAP fault to be defined in the WSDL, since we have HTTP error codes. We do not necessarily need WS-Security as we have OAuth/OpenID/etc token based federated security. Discovery is not really a big issue and hypermedia can help in this regard. 

OK, the question is do we need all that stuff? REST (and HTTP as its sole implementation) is Turing-complete. An agent should not need any priori knowledge to be able to use a service. It can use OPTIONS to discover verbs, it can use content-negotiation to ask for media types it can understand and use hypermedia to navigate through the resources of a server.

Turing-completeness is great but to be honest, it still belongs to Sci-Fi novels. We are not there yet. I believe for great development experience and maintenance, we still need schema. Most web APIs are about interacting with data. Probably somewhere around 80-90% of Web APIs out there serve JSON. What does application/json content type exactly tell about the actual JSON being served? Are we currently writing agents/applications that can intelligently adapt and consume whatever JSON being served to them? 

I was listening to one of the episodes of MashThis podcast and the theme that was coming on good Web API was always good documentation. Nothing beats a good documentation but how many of us developers are good in this? Human effort to create and maintain a good documentation covering schema and description is going to be big. I think we need some automation here.


Challenges

I originally suggested using media types so that client could request not the data but the schema of the data. In this update, I am going to look at other options as well as semantic challenges for providing schema and description. In fact, I am not going to propose a solution, I will use this post to describe the problem. I hope this will start a fruitful discussion so please feel free to join in.

HTTP and schema?

Schema for an HTTP API (intentionally not using the word REST API) might initially seem a little bit odd. Actually the word does not appear at all in the RFC 2616. As far as the HTTP is concerned, server will allow the agent to interact with the resource using URI using the verb and associated headers. It is up to the agent to engage in content negotiation and interpret the result.

I personally think the problem of schema and description is inherently orthogonal to HTTP. A resource does not necessarily have to have a schema - other than the schema assumed by the content-type. For example, when a server responds to a GET request for an XML page using /foo/api/2 URL, it just serves the page which ideally is conformant to XML schema. But even well-formed XML does not explain enough about the structure of the document and its internal schema. In fact XML instance will contain its schema but server (unlike RPC style web services) might not able to return an XML schema - since /foo/api/3 might have a completely different schema.

But let's bear in mind this can simply be an option. Server might support the schema/description and return, or it can return a 404 error. In fact, schema can be service-specific or URI specific, i.e. it could refer to /foo/api/{id} or /foo/api/690. In this case, while schema is relevant for different ids (as they have different schema), service description will be the same. Hence any solution must consider this variability.

URIs and URIs routing formats

It is very common in the Web API space to provide URIs containing placeholders to pass data fragments to the API. In our example, /foo/api/690 means id=690. Alternatively, data could be sent as query string parameter such as /foo/api?id=690.

The schema or description could be different based on the parameters passed.

One issue to be considered is that it is possible agent does not know about an actual existing resource (for example does not know a valid id to be passed to return an actual resource) and all it knows is the URI format. Solution must be flexible enough to provide a schema for the API method if a generic schema exist for the URI format (i.e. all documents at /foo/api/{id} have similar schema)

Priori knowledge

One of the main focuses of HTTP spec is to remove the requirement of the priori knowledge from the agents. Agent is encouraged to explore server resources and functionality (e.g. OPTIONS) and server guides the agent using hypermedia.

With developing Web API that requires documentation, we are adding back this priori knowledge requirement. This is not good. But in the absence of a standard we will end up with nothing much better than a convention - which itself is a priori knowledge. So ideally this process must involve a standard or even a standard proposal. A lot of useful technologies out in the cloud are still in the proposal phase, namely OData, JSON Schema and HAL.

Security

A schema must ideally provide a detail on the security requirements of the service. This is especially important for authentication schemes supported by the server (e.g. basic authentication, federated identiy, etc).

Schem and description as a single resource?

Decision needs to be taken to whether serve description and schema of the service separately or provide them as a single document. The more I think about it, the more I feel it probably has to be a single document.

Possible Solutions


1- Using content type

Since JSON and XML are two most popular formats being served, for now serving schema can practically be limited to these media types.

Let's Look at this request:
GET http://localhost:50459/api/HelloWorld/1.1
User-Agent: Fiddler
Host: localhost:50459
And response is:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Tue, 17 Apr 2012 21:46:38 GMT
Content-Type: application/json; charset=utf-8
Connection: Close 
"This"
So as we can see, media type returned is JSON and the value is a simple string. Now if we send a request asking for a JSON schema with accept header of  application/schema+json, we get back this:

GET http://localhost:50459/api/HelloWorld/1.1
Accept: application/schema+json
Host: localhost:50459 
And response is:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Tue, 17 Apr 2012 21:46:38 GMT
Content-Type: application/schema+json; charset=utf-8
Connection: Close 
{
  "type": "string"
It is true that JSON schema is still in draft status but with this format becoming more and more popular, it is inevitable that we restore some structure in our Web API.

Since XML already has an established schema language, we can use XML Schema but one problem is that XML Schema has a content type of application/xml or text/xml. So either we nominate an alternative content type (such as application/schema+xml) or use URI to denote request for schema (ideally in the format of optional query string parameter although that will still be part of the URI).

Same applies to the description of the service. It is ideal that the documentation of the service id provided by the service itself. For description, agent can use a special content type (for example x-text/docs) or using a query string parameter.

2- Using hypermedia

Server can include separate links to schema and description while serving the actual resource. Payload can be HAL or alternative implementations of hypermedia.

A HAL payload can look something like:

{
  "_links": {
    "description": { "href": "/description" },
    "schema": { "href": "../../schema?type=MyDto" }}
  },
  "_embedded": {
    "MyDto": [
...

Server could have an implementation convention to treat description and schema URL fragments as special paths and serve appropriate resources. Please note that all the data needed to provide the schema could be located in the URL, e.g. type of the serialised payload is appended as a query string parameter so the server does not even have to know about the API method queried about.

This imposes a burden on the agent to understand such complex structures.

Also bear in mind, an ideal solution must be able to explain the output schema as well as input schema. For POST and PUT verbs, a JSON payload could be sent to the server to be stored and server must be able to provide not only the output but also input schema.

3- Using a URL convention

Basically in this solution, agent has a priori knowledge of a convention (or a standard) by which can interrogate the server and ask for schema and description of the services available on the API server. For example /foo/api/$list could provide a list of methods (I know, it sounds like RPC but I have no better word) avilable on the server. $schema can provide the schema and $description the description for the service.

Conclusion

Web API needs to look back and consider solving some of the problems solved by classic Web Services. It is very likely that with the migration of classic web services to Web API we find ourselves in a chaotic situation. This area needs to be explored and all options to be considered hence a debate on the subject is welcome. It is likely that we might need a convention/standard for describing our Web APIs.

No comments:

Post a Comment