Friday, September 26, 2014

How to create a Web API no one wants to use: Exercises

Introduction to this blog series


Later this year, Netflix will be closing their public APIs. Twitter and Google have already restricted their APIs. Despite prominent tech-companies making drastic changes to their APIs, the number of APIs keeps growing steadily. Suddenly, everyone has a Web API. Your car has one, Chuck Norris has one, and worst of all, tech-companies with no focus on quality whatsoever has one. And who are using these APIs? Most likely, no one.
This blog series will take you through the pitfalls of creating a Web API. From a developers perspective, what mistakes will result in no one wanting to use your API?

Part 1: URI Design
Part 2: HTTP Verbs
Part 3: HTTP Status Codes
Part 4: Result formatting
Part 5: Versioning
Exercises

Exercises


Earlier this week I presented my "How to create a Web API no one wants to use" talk at Code Pub Oslo. Code Pub Oslo is a meetup for female developers, a very inspiring event! The organizers asked me to create a set of exercises to go with the presentation, and here's the result.

Exercise 1: URI Design


Imagine you have an API with the following endpoints:

EndpointDescription
…/books/Returns all books
…/books/id/5Returns the book with ID=5
…/author/Returns all authors
…/author/3/booksReturns all books written by the author with ID=3

a) Can you spot any inconsistencies in this API? How would you fix them?
b) Can you redesign the API so that the URIs are hackable?
c) Can you think of an alternative way of filtering the books on author?

Exercise 2: HTTP Verbs


a) Which of these methods are safe?
i. Registering a new user
ii. Retrieving the weather forecast for tomorrow
iii. Cancelling an order
iv. Removing a picture

b) Which of these methods are idempotent?
i. Registering a new user
ii. Retrieving the weather forecast for tomorrow
iii. Cancelling an order
iv. Removing a picture

c) Which verb should you use for the following methods?
i. Registering a new user
ii. Retrieving the weather forecast for tomorrow
iii. Cancelling an order
iv. Removing a picture

Exercise 3: HTTP Status Codes


Which status code should you return in each case?
a) The client asks for a record that does not exist
b) The client posts invalid data
c) There was a technical error in the API
d) The client creates a new record
e) The client calls an asynchronous method

Exercise 4: Result Formatting


You are developing an API for a customer who wants to support both JSON and XML results. Which type of result formatting should you go for?

Exercise 5: Versioning


a) You are developing an API for a customer who wants the version to be an optional part of the URI. Which versioning method should you use?

b) What if the customer wanted the client to specify both the version and the result format as part of a header?

c) Can you give an example of how such a header would look?


Wednesday, September 24, 2014

Find purchase orders by an OrderForm meta field in EPiServer Commerce

If you've added a meta field to an OrderForm, you can use the OrderContext.Current.FindPurchaseOrders method to find all purchase orders with a given value in that meta field. However, figuring out what the SqlWhereClause should be might not be completely straight forward, so I thought I'd share a solution.

I've added a meta field to the OrderForm called OrderStatus. This meta field will then show up as a new column in the OrderFormEx table in the Commerce database:



What if I want to find all purchase orders where OrderStatus is NULL? The following code would do the trick:

var searchOptions = new OrderSearchOptions
{
   CacheResults = false,
   Classes = new StringCollection { "PurchaseOrder" },
   Namespace = "Mediachase.Commerce.Orders"
};

OrderSearchParameters parameters = new OrderSearchParameters()
{
   SqlWhereClause = "OrderGroupId IN (SELECT OrderGroupId FROM OrderForm WHERE OrderFormId IN (SELECT ObjectId FROM OrderFormEx WHERE OrderStatus IS NULL))"
};

PurchaseOrder[] purchaseOrderCollection = OrderContext.Current.FindPurchaseOrders(parameters, searchOptions);

If you want to know more about how this works, you should check out EPiServer Commerce Order Search Made Easy (not sure I agree on the "made easy" part, but that's a different story).

Hopefully this will save you some time! 

Thursday, September 18, 2014

Using StructureMap with named instances in EPiServer

If you have several classes inheriting from the same interface, and you want your business logic to choose the correct class based on a criteria, you should check out named instances in StructureMap.

For example, let's say you have the following classes:

public class Facebook : IAuthenticationStrategy
public class Google : IAuthenticationStrategy
public class Forms : IAuthenticationStrategy

We have three implementations of IAuthenticationStrategy and the role of these classes is to validate the authentication credentials for Facebook, Google and Forms authentication.

Now, let's define the criteria as an enum:
public enum AuthenticationType
{
    Facebook,
    Forms,
    Google
}

If the user selects Facbook during login, the business logic validating the authentication will receive AuthenticationType.Facebook. If Google is selected, AuthenticationType.Google is used, and so on.

How can we use named instances in StructureMap to wire all this up? Let's define all our instances of IAuthenticationStrategy in our container:

container.Configure(
    x =>
    {
       x.For<IAuthenticationStrategy>().AddInstances(i =>
       {
          i.Type<Facebook>().Named(AuthenticationType.Facebook.ToString());
          i.Type<Google>().Named(AuthenticationType.Google.ToString());
          i.Type<Forms>().Named(AuthenticationType.Forms.ToString());
       });
});

Now all we have to do is create a Factory class passing in the AuthenticationType the user has selected:

public class AuthenticationFactory : IAuthenticationFactory
{
    public IAuthenticationStrategy Create(AuthenticationType type)
    {
         return ServiceLocator.Current.GetInstance(typeof(IAuthenticationStrategy), type.ToString()) as IAuthenticationStrategy;
    }
}

Last, but not least: Here's an example of how you could use the AuthenticationFactory to receive the correct instance:

public UserAuthentication ServerValidate(UserAuthentication userAuthentication)
{
    IAuthenticationStrategy authentication = _authenticationFactory.Create(userAuthentication.Type);
    return authentication.ServerValidate(userAuthentication);
}

Simple, right?

Tuesday, September 2, 2014

How to create a Web API no one wants to use. Part 5: Versioning

Introduction to this blog series


Later this year, Netflix will be closing their public APIs. Twitter and Google have already restricted their APIs. Despite prominent tech-companies making drastic changes to their APIs, the number of APIs keeps growing steadily. Suddenly, everyone has a Web API. Your car has one, Chuck Norris has one, and worst of all, tech-companies with no focus on quality whatsoever has one. And who are using these APIs? Most likely, no one.
This blog series will take you through the pitfalls of creating a Web API. From a developers perspective, what mistakes will result in no one wanting to use your API?

Part 1: URI Design
Part 2: HTTP Verbs
Part 3: HTTP Status Codes
Part 4: Result formatting
Part 5: Versioning
Exercises

Versioning

One of the first things you should think about when creating a Web API is how to handle versioning. However perfect you make your API, you're bound to find a way that's even more perfect before long, and then you'll need to launch a new version. If you haven't already planned out how your versioning should work, the lauch of a new version might be painful for the developers consuming your API. 
As RESTful APIs are growing in popularity and we see the number of SOAP APIs decreasing, my impression is that the focus on version handling is becoming better. Where developers previously put a number at the end of their method name, they now decide on an overall strategy for their API. 
Example: PayEx API
An example of the terrible "I'll just put a number at the end" versioning that arised with SOAP can be seen for example in the PayEx API. If we have a look at the PxOrder webservice, it contains the following methods: 
  • Cancel2
  • Capture5
  • Check2
  • Complete
  • Credit5
  • CreditOrderLine3
The developers consuming your API have no way of knowing whether the Cancel2 method is compatible with the Capture5 method, and this makes your API difficult to work with! 
So, what is the correct way of versioning your API? There isn't one. There are several possibilities, but there isn't 'one' correct that you should be using. Whichever way you pick, someone will claim that the one you picked is wrong, so pick the one you feel makes the most sense for your API. What's important is that a new version should not break the existing versions for the users of your API. 
Solution 1: URL versioning
Putting the version number in the URL is a quite popular approach. One of the APIs that does this is the Twitter API
GET https://api.twitter.com/1.1/trends/place.json?id=1
The upside of URL versioning is that you can quite easily change the structure of your API in the next version without breaking any changes for users wishing to stay with an older version. In addition to this, there is never any confusion as to what version of the API you are using, you can send the URL to someone else and they will see the same version of the API as you. The downsides to this approach is that you might have to maintain quite a large number of URLs as time goes by, and clients wanting to upgrade to a newer version will have to change all their URLs. Last, but not least, there is no way for the developers consuming your API to say: "Always give me the newest version of your API". Instead they have to say "Give me version X of your API".  
Solution 2: Query string parameter
Including the version number as an optional query string parameter makes it possible for developers consuming your API to always get the newest version. An API that lets you do this is the Netflix API
GET http://api-public.netflix.com/catalog/titles/series/7002352?v=1.5
Others prefer to use the date of the version release instead of the version number, for example FourSquare:
GET https://api.foursquare.com/v2/venues/40a55d80f964a52020f31ee3?oauth_token=XXX&v=YYYYMMDD
In both cases, leaving out the version query string parameter will result in the newest version being used. And creating a new version will never change the URL, only the query string parameter changes. This kind of versioning is great when the changes done from version to version are small. If there are any breaking changes from one version to another, and the users of your API are using the latest version, you might be breaking their code. "Breaking changes", get it?
Solution 3: Vendor Specific Accept Header

In part 4 of this blog series, we saw how we could use Content Negotiation with Accept headers for determining the result formatting. The same can be done for versioning, and it's often used in combination with result formatting in what we call "Vendor Specific Accept Header". The format for this is:
HEADER Accept: {type}/vnd.{company}.{version}+{type}

The GitHub API for example uses:
HEADER Accept: application/vnd.github.v3+json

This Accept header tells us that we want the results as application/json, and we're using version 3 of the API. By using Vendor Specific Accept headers, all URLs will be the same for any version of the API, which is good since one resource should only have one URL. However, there are some downsides to this approach as well. Changing the headers is not always a walk in the park, so it might make the API harder to use for some developers.
Solution 4: Custom Request Header

Instead of using the Accept Header as we saw in the previous example, some APIs create their own Custom Request Headers. An example is the Azure Storage Services API:
HEADER x-ms-version: 2014-02-14

The upside of creating your own Request header is that the version request header only determines the version. In our previous example of using a Vendor Specific Accept header, the type also had to be included. Again, all URLs will be indentical for any version of the API, but we still have the same issue of request headers not always being easy to modify.

Solution 5: All of the above?

If you're feeling really awesome, you can follow the example of Troy Hunt. He decided that since every type of versioning would be considered wrong by some, he would implement three different ones in his API to please the crowd. His blog post "Your API versioning is wrong, which is why I decided to do it 3 different wrong ways" is definitely worth a read!

Summary


Versioning is difficult as everyone has different opinions as to which way is the "right" way. What's important though is that you decide on a versioning strategy from day one so that it doesn't come as a surprise to you later when you decide to improve your API. Whatever you do, DO NOT break your clients code! And of course, care about your API from the very first piece of code you write.

Monday, September 1, 2014

How to create a Web API no one wants to use. Part 4: Result Formatting

Introduction to this blog series


Later this year, Netflix will be closing their public APIs. Twitter and Google have already restricted their APIs. Despite prominent tech-companies making drastic changes to their APIs, the number of APIs keeps growing steadily. Suddenly, everyone has a Web API. Your car has one, Chuck Norris has one, and worst of all, tech-companies with no focus on quality whatsoever has one. And who are using these APIs? Most likely, no one.
This blog series will take you through the pitfalls of creating a Web API. From a developers perspective, what mistakes will result in no one wanting to use your API?

Part 1: URI Design
Part 2: HTTP Verbs
Part 3: HTTP Status Codes
Part 4: Result formatting
Part 5: Versioning
Exercises

Result Formatting

The developers consuming your API will have varied opinions as to what format they want their results in. Supporting only XML might make developers who prefer JSON, JSONP or Turtle turn to other APIs instead of yours. In order to please the users of your API and to make sure you're not dictating the formats, you should support at least a few of the most common ones.

Example: Norwegian Meteorological Institute's Weather API

The Norwegian Meteorological Institute's Weather API provides forcast data for it's users. What we are interested in knowing is how they format their results. Let's ask for the sunrise data for Oslo, Norway:
GET http://api.met.no/weatherapi/sunrise/1.0/?lat=59.922086;lon=10.752844;date=2014-08-16

And we receive an XML result. According to ProgrammableWeb, XML is on decline and more and more API users prefer JSON (http://www.programmableweb.com/news/1-5-apis-say-bye-xml/2011/05/25). So APIs only supporting XML is decreasing in popularity:


Obviously, formatting your results only in XML is not a good idea then, you should also support other formats. So how are Web APIs out there doing that? Let's take a look at some of the different solutions:

Solution 1: URL extension

Some APIs let the user specify the format they want as a URL extension. I'm not a huge fan of this solution, but it's better than not supporting multiple formats so let's have a look at it.

In part 1 of this blog series, we had a look at the URI design of the U.S. City and County Web Data API. Let's ask for all links they have for Chicago, Illinois:
GET http://api.sba.gov/geodata/all_links_for_city_of/chicago/il

This request gives us XML in return. Now, let's ask for the same thing, specifying that we want the result in JSON:
GET http://api.sba.gov/geodata/all_links_for_city_of/chicago/il.json

We use the same URL, but we add 'json' as an extension. We can also add 'xml' as an extension and get the same result as we got when we didn't specify the format. In other words, if you don't supply a format extension, the fallback is XML.

The problem with using URL extensions for result formatting is that your API will have two different URLs that supply the same data. Having two separate URLs suggest that these are two different resources. However, they are not different resources, they are simply two different representations of one resource. So let's try another approach!

Solution 2: Query string parameter

A lot of APIs accept the format as a query string parameter, which of course solves our previous issue of having several URLs for the same resource.

In part 1 of this blog series, we analyzed the URI design of the World Bank API and as we saw then, they use a query string parameter to specify result formatting. Let's get all the countries:
GET http://api.worldbank.org/countries/all

As in our previous example, not specifying a format defaults to XML. So our request above is identical to:
GET http://api.worldbank.org/countries/all?format=xml

Now, if you want the result in JSON instead, you set format=json:
GET http://api.worldbank.org/countries/all?format=json

As you can see, each resource only has one URL and the different representations can be retrieved by including a query string parameter. But what if we don't want to specify the format, what if we instead want to say "These are the formats I support, give me one of them"? This can not be done with a query string parameter, and that brings us over to Content Negotiation.

Solution 3: Content Negotiation

Best practice when it comes to result formatting is considered to be Content Negotiation. Using Content Negotiation, the client tells the API which formats he is able to accept, and the API selects the first suitable format. Let's take a look at how the Facebook Graph API uses Content Negotiation. By default the API returns its results as text/javascript:
GET http://graph.facebook.com/daft-punk

However, if you want the result as JSON, you need to add an Accept header to your request:
HEADER Accept: application/json
GET http://graph.facebook.com/daft-punk

The Content-Type of the response will now be JSON instead as you've specified that you prefer JSON. You can add several formats to the Accept header. Let's see what happens when we add both JSON (which the API supports) and XML (which it doesn't support):


The Content-Type of the response is still JSON as the API picked the only format it knew it supports. Let's add another format to the Accept header, the text/turtle format.


In this request, we've added three formats to our request Accept header: application/json, text/xml, and text/turtle. The API only supports the first and the last, and therefore it picks the last one in the list.

By supporting Content Negotiation, you allow the users of your API to give you several options as to what result format to return. And that's how you make your API a walk in the park to work with.

Summary


When you're developing an API, it's important to remember that the users will all want different things and they all prefer different formats. There are several ways of letting your users specify the format they want, for example by using URL extensions, query string parameters or Content Negotiation via accept headers. There's a lot of discussion as to which of these is the "most correct", but what's most important is that you give your users a choise and care about your API from the very first piece of code you write.