DPS907 notes – Tue Oct 15

Hypermedia-driven web API design.

.

Modern web APIs should be hypermedia-driven.

This means that the response will include the data that you expect, and it will include links that enable you – the requestor – to determine what to do next.

The web API author should not have to provide out-of-band documentation or knowledge.

Your professor will use a web browser and web page analogy to help you understand this concept.

This concept was identified in the hypermedia constraint section of Roy Fielding’s PhD thesis.

Architectural Styles… thesis, by Roy Fielding; REST is discussed in Section 5

REST APIs must by hypertext-driven, in which Roy reminds us about some design principles

.

Data and metadata available to the web API designer and user

This is a brief reminder of the list of data items and metadata that are available to web service designers and users.

  • HTTP method
  • URI
  • Request headers
  • Response headers
  • Message body, in general
  • Representation (of a resource)

Today, you will learn something about these:

  • Link relations
  • HTTP OPTIONS method
  • Representations that enable a user/requestor to add a resource

.

A brief discussion of ‘links’…

Web client programmers are familiar with the ‘link’ element ( <a> ) in HTML. You also know that the “HT” part of HTML expands to “hypertext”.

What’s at the other end of a link in HTML? Text? Always? Or can it be an image, a video, or some other media?

So, just change your understanding a bit, so that a link is a ‘hypermedia’ link, and not just a hypertext link.

In a web API, links are used to tell the requestor about state transitions. In other words, they tell the requestor what can be done next.

For example, assume that a requestor asks for a single-item resource. The web service returns a representation (the data) for that resource. It would be nice to include data and/or metadata that would tell the requestor whether that resource could be modified, or deleted. Or whether it was possible to add a new resource to the resource’s parent/collection.

.

Link relations

The solution is to use link relations. Using this solution, the response includes links that can guide the user through state transitions.

A link is a data object, delivered in-band, with the representation. When you define a link in a web service, you must also define its relationship to the current object.

For example, a single object must include a link to itself:

  • The value of the URI (aka href) will be the item’s URI
  • The value of the relationship (aka rel) will be ‘self’

If it’s part of a collection, it must also include a link to its parent/collection:

  • The value of the URI (aka href) will be the item’s parent/collection
  • The value of the relationship (aka rel) will be ‘collection’

This design ensures that the responses from your web service are self-describing.

The IANA has published a list of standardized link relations. You can create your own, but use the standard link relations until you gain more experience.

.

Code example for today’s topics

From the code example repository, look at LinkRelationsIntro.

.

Preview of our design and coding plan

In general, we will follow these steps:

  1. Start with an existing project that works well.
  2. Add new ‘view model’ classes that support and enable link relations.
  3. For an entity, add new ‘view model’ classes that include link relations. Add new AutoMapper definition(s).
  4. Update ‘controller’ code. Wrap the fetch result(s) in a view model class that includes link relations, and configure the links.
  5. Add support for the HTTP ‘OPTIONS’ method.
  6. Configure an entry point URI for the web service.

.

Are there standards (for expressing link relations) that we must follow? No.

In today’s example, we create our own representations.

In the future, we may look at HAL and/or Collection+JSON. It’s possible that you may use one of those in the future (or design your own).

.

Start with an existing project that works well

You will learn this topic more effectively if you use an existing project that works well.

Create a copy of that project, using the copy-then-rename technique you learned a few weeks ago.

.

Add new ‘view model’ classes that support and enable link relations

Create a new source code file – perhaps named VM_Link – to the ViewModels folder.

It will hold classes that support and enable link relations.

.

Overview of the design

There will be two versions of our class that supports link relations: 1) one item, and 2) collection of items.

object-item-jsonFor one item (click the image to see it full-size in a new tab/window):

  • The class has two properties, ‘Links’ and ‘Item’
  • ‘Links’ is a collection of one or more Link objects
  • One Link is to ‘self’
  • Another Link is to its parent ‘collection’
  • ‘Item’ is the actual fetched result
  • The ‘Item’ also includes a Link to ‘self’

object-collection-jsonFor a collection of items (click the image to see it full-size):

  • The class has two properties, ‘Links’ and ‘Collection’
  • ‘Links’ is a collection of one or more Link objects
  • One Link is to ‘self’
  • ‘Collection’ is the actual fetched results
  • Each ‘Item’ in the collection includes a Link to ‘item’

.

Write the classes

We will need a Link class to model a hyperlink. At a minimum, it will need href and rel properties.

If you wished, in a future project, you could consider adding other properties, such as title, method, and type.

.

Abstract class in C# 

It’s possible that you have not written an abstract class yet.

An abstract class is use used as a base class that another class inherits from. By itself, that’s nothing special.

Our situation is different. In our app domain data model, it’s possible that we may have a large number of ‘entity’ classes. Then, for each entity class, we will have some ‘view model’ classes.

An abstract class will reduce the amount of code we write, if we also take advantage of generics and type injection. So, let’s do that: Write an abstract class, for a single item, that includes a T (type) parameter, as shown below:

abstract-class

.

Do the same to create an abstract class for a collection of items.

.

For an entity, add new ‘view model’ classes that include link relations
Add new AutoMapper definition(s)

Our goal is to add a Link property to a suitable view model class. That’s easy.

Then, remember to go the Global.asax.cs source code file and add an appropriate AutoMapper definition.

.

Update ‘controller’ code
Wrap the fetch result(s) in a view model class that includes link relations,
and configure the links

Now, we have to update the code in a controller. We’ll focus on the get-all and get-one methods.

The beginning part of a controller method works the same. It calls a repository method, and a result is returned. The result can be a single item, a collection of items, or null.

Our goal is to ‘wrap’ the result(s) in the new view model class that includes link relations.

Based on what you’ve learned earlier, the code in the method does the following:

  1. Create an object (item or collection) that supports link relations
  2. Add a Link to ‘self’
  3. If you’re configuring an ‘Item’, add a Link to the ‘collection’
  4. Set its ‘Item’ or ‘Collection’ property to the fetched result(s)
  5. If you’re configuring a ‘Collection’, add a Link to ‘item’ to each item
  6. Return the now-full-configured object

.

Add support for the HTTP ‘OPTIONS’ method

A hypermedia-driven design needs to support the HTTP OPTIONS method.

This enables a requestor to determine what HTTP methods are supported by a URI, before sending the actual request.

The recommended approach is to create a ‘handler’, which will intercept and process any request that uses the OPTIONS method. This is a better alternative to writing code in every controller.

Your professor will explain the design and function of the HttpOptionsMethodHandler class during the lecture. It uses the same ApiExplorer functionality that the ‘Help’ page depends upon.

Your professor acknowledges the post by Jef Claes that enabled today’s handler to get written. Then, Yao Huang Lin’s post provided the knowledge that resulted in it covering all kinds of URIs.

.

Configure an entry point URI for the web service

A hypermedia-driven design also needs an ‘entry point URI’.

The idea is that the web service provider can publish one single URI for the web service, and clients/requestors will be able to discover all of the resources.

To do this, we must perform these steps:

  1. Add a default value for the ‘controller’ placeholder, in the App_Start > WebApiConfig class
  2. Add a new ApiController class that uses the value you provided above
  3. Implement a single ‘get’ method, which returns a collection of link relations

.

Bonus! Deliver a template for an ‘add new album’ request

This was a last-minute addition to the topic set today.

Here’s a scenario: A user of your web service wants to add a new ‘album’ object. What properties must be provided? Data types? Other constraints?

The solution is to deliver a template with the response to the ‘get-all’ request. That’s the most natural place for it, because we’re already delivering a link relation for the collection.

How do we implement this? Two tasks:

  1. Add a view model class for the template
  2. Add a property to the ‘get-all’ link relations container class for a template object

.

Add a view model class for the template

Add a view model class for the template. In the code example, it is named “AlbumAddTemplate”.

It has string properties. The property names match – exactly – the names of the properties in the “AlbumAdd” view model class.

All properties have getters only. No setters. When initialized, the class object has all it needs to ‘tell a story’ to the user.

The property values will tell the user about the data they must send, including data types and other constraints (length, range, etc.).

.

Add a property to the ‘get-all’ link relations container class

Add a property to the ‘get-all’ link relations container class. Add a default constructor to initialize the property’s value.

.

.

.

.

.

.

.

.

.

.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: