DPS907 notes – Tue Oct 4

Application state changes with hypermedia-driven design, and link relations.

 

Test today

The weekly test will be done at the beginning of the class timeslot at 11:40am.

 

Code examples

In the GitHub code example repository for this week, you will see several interesting assets.

The LinkRelationsIntro code example will be studied today, and discussed in the notes below.

HandleHttpOptions.cs is a class that you can add to a project, and it will handle HTTP OPTIONS requests.

Links_vm.cs includes classes that enable link relations for any of your resource model classes.

Soon, another code example, LinkRelationsMore, will be posted, and we’ll discuss that in the Thursday class/session.

Also, version 2 of the project template will be posted soon.

 

Reminder – use the Visual Studio Task List…

Make sure that your Visual Studio app is configured to use the “ATTENTION” comment token.

Then use Visual Studio’s “Task List” to help you study the design and coding features of the code example.

 

Hypermedia-driven web API

Modern web APIs, for public use, must be hypermedia-driven.

What does this mean? It means that the response will include:

  • the data that you expect, and
  • 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 to the user of the web API.

Instead, the user of the web API should be able to “discover” functionality, found in the links, to drive the logic and workflow of their app.

This concept was identified in the hypermedia constraint section of Roy Fielding’s PhD (doctoral) thesis, “Architectural Styles and the Design of Network-based Software Architectures”.

Who is Roy Fielding?

A giant in our industry. We owe him so much.

Oh, and when you look at the list of authors of the RFC 7230 series, he’s the principal author. Then, look back at the now-obsolete predecessors to this series: 2616, 2068, and 1945. He’s on the author list on those, too.

Incidentally, another name on the author list is “H. Frystyk”. That would be Henrik Frystyk Nielsen. Working at Microsoft, he is one of the developers of and contributors to the framework that powers ASP.NET Web API. Yes, really.

 

How can I understand this concept better?

Study the following screen capture. (Click to open it full-size in a new tab/window.)

web-page-1

 

How do you use this page? What is its purpose? What can you do next?

Next, study the following screen capture. (Click to open it full-size in a new tab/window.)

web-page-2

 

How do you use this page? What are its purposes? What can you do next?

Finally, study the following screen capture. (Click to open it full-size in a new tab/window.)

web-page-3

 

How do you use this page? What are its purposes? What can you do next?

With all three pages – any ANY page you view in a web browser – you innately know what you can do next. You can view the content. You can click links (including the browser’s “back” link). You can enter some data and process that data.

How can you implement this – what can you do next? – in a web service?

With link relations. That’s today’s major topic.

 

Where can I learn more about hypermedia-driven design?

Please read the following two documents:

1. Section 5 of Roy Fielding’s Architectural Styles… PhD (doctoral) thesis.

This is a readable and understandable thesis, but some readers will need more effort to get through the recommended Section 5, “Representational state transfer” (REST). Take your time, and skim when necessary.

Near the beginning, Roy identifies the now well-known REST constraints:

“…multiple architectural constraints are needed to guide the behavior of [software] components. REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state. These constraints will be discussed in Section 5.2.”

Yes, the constraints are discussed in Section 5.2. However, the hypermedia-driven concept is better explained in Section 5.3.3. The last paragraph of the section brings out this idea clearly:

“The model application is therefore an engine that moves from one state to the next by examining and choosing from among the alternative state transitions in the current set of representations. Not surprisingly, this exactly matches the user interface of a hypermedia browser. However, the style does not assume that all applications are browsers.”

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

 

Conflicting opinion – it does not matter

Before continuing, we should present and discuss a conflicting opinion: Hypermedia-driven design does not matter.

Transforming a web service to a hypermedia-driven design takes effort, and must be done correctly. It’s a lot of work.

Consider a scenario where a web service was created as part of a new system’s architecture and design. Further, the web service, and the applications that use it, will be used inside an organization only. In other words, it will not be publicly-accessible. The programming teams that are developing the web service and the applications are unified, or at a minimum, they collaborate during the development process.

In this kind of scenario, the web service and the applications have knowledge of state changes, workflow, object graph shapes, and so on. Documentation is also likely shared, so the teams have a vast amount of information and understanding.

So… Does it matter in this scenario? You could argue “no” in a convincing manner.

Software architect Ben Morris does indeed do this, in his post…

Pragmatic REST: APIs without hypermedia and HATEOAS

Please keep this in mind in the future. You may find yourself in a situation where you face this kind of choice. With a bit more experience in this and related fields, you will be able to bring value to the decision-making progress.

 

Data and metadata available to the web API designer and user

The following list 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:

  1. Link relations
  2. The HTTP OPTIONS method
  3. Hypermedia representations, which include additional data that enables a user/requestor to learn about the data that’s needed to add a new resource

 

A brief discussion of “links”…

Web client programmers are familiar with HTML “link” elements:

  • a
  • img
  • link

You also know that the “HT” part of HTML expands to “hypertext”.

So… what kind of data is at the other end of a link in HTML?

Text?

Always?

Or can it be an image, a video, or some other media?

Yes, certainly the data could be any kind of internet media type.

Therefore, to help you make progress learning this topic, simply change your understanding (of a link target’s data type) a bit, so that you begin to think of a link as a “hypermedia” link, and not just as a hypertext link.

 

How do we use links in a web API?

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 (e.g. a product). 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.

This is what Roy Fielding means when he writes that “hypermedia [is] the engine of application state”.

 

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, by convention, a single object must include a link to itself:

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

If the single object is part of a collection, it must also include a link to its parent/collection:

  • The value of the URI (href) will be the item’s parent/collection
  • The value of the relationship (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.

 

Handling an HTTP OPTIONS request

A hypermedia-driven design must support the HTTP OPTIONS method.

From RFC 7231:

“The OPTIONS method requests information about the communication options available for the target resource…  This method allows a client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action.”

 

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

Instead of using GET with a request URI, use OPTIONS with a request URI.

The response will include a response header named “Allow”, with a comma-separated list of HTTP method names that can be used with the URI. It’s as simple as that. (The entity body is empty.)

Does the Web API project automatically handle OPTIONS requests?

No. We must write code to do this. For example, in a controller, you could write a method that handles the request. Notice return type, HttpResponseMessage:

[HttpOptions]
[Route("api/products")]
public HttpResponseMessage AvailableOptions()
{
    // Create a response object
    var response = new HttpResponseMessage(HttpStatusCode.OK);
    // Initialize the content property
    response.Content = new StringContent("");
    // Add an "Allow" header, with the allowable methods for this URI
    response.Content.Headers.Add("Allow", "GET,POST");

    return response;
}

 

Do we need to write this kind of code in every controller? Yes.

For every URI pattern? Yes.

That would be annoying.

Is there a better way? Yes.

The recommended approach is to create a “message handler”, which is a software component that plugs into the request-processing pipeline. It will intercept and process any request that uses the OPTIONS method. The request is serviced by a single module, and it returns a useful response to the requestor. This is a much better alternative to writing code in every controller.

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

 

Implementing an HTTP OPTIONS handler

Instead of writing this handler from scratch, students in Prof. McIntyre’s Web Services course have permission to use the code that’s found in the HttpOptionsHandler code example folder. (The folder does not include a complete project – just the source code file that you need.)

Just copy the HandleHttpOptions.cs source code file into any existing project, change its namespace name to match your project, add it to the Register method body in the WebApiConfig class, and it will just work.

You’re welcome.

Study the code, to learn how it works.

 

Representations that include hypermedia

At this point, we have introduced link relations. And, handling requests that include the HTTP OPTIONS method.

Now, we will design and code a representation that will include hypermedia. It will still be a JSON-based representation, but it will include data that will tell the user how to change the application state of the web service.

 

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 resource model classes that support and enable link relations.
  3. For an entity, add new resource model classes that include link relations. Add new AutoMapper definition(s).
  4. Update controller code. Wrap the fetch result(s) in a resource 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 in representations?

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). Mike Amundsen is very interested in hypermedia representations, and has much to offer in this topic area.

Let’s get started on the steps listed above…

 

Start with an existing project that works well

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

 

Add new resource model classes that support and enable link relations

Create a new source code file – perhaps named Links_vm – to the Controllers folder.

It will hold classes that support and enable link relations.

 

Overview of the design

There will be two versions of our design that supports link relations:

  1. a class for one item, and
  2. a class for a 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 titlemethod, and content type.

 

Abstract class for the linked item

An abstract class will reduce the amount of code we write for resource models, 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-structure

 

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

 

Best practice recommendation – use the professor’s Links_vm.cs code

While you could write the link classes yourself, your professor recommends that you use the classes in the Links_vm.cs source code file. You have permission to use the code as-is. (Remember to change the namespace name, to match the name of your project.)

They are highly functional, and have been tested with many entities, scenarios, and use cases.

 

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

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

Then, remember to add an appropriate AutoMapper definition. The source class/type will be whatever is returned from the manager method call. For example, EmployeeBase. The destination class/type will be the new EmployeeWithLink.

 

Extra tasks to be done with Chinook entities

You have noticed that the Chinook sample database entities use a composed name for the identifier property. For example, EmployeeId, CustomerId, InvoiceId, etc. This is different than our best practice recommendation, where identifier properties are simply named “Id”.

Composed names are not used by the link class factories. They rely on a convention where the identifier is named “Id”.

Can we fix this? Yes, with two actions.

First, in the EmployeeWithLink resource model class, add another property, an integer, named “Id”.

Second, in the AutoMapper “create map” statement, add a “projection” method, which will cause the value of “EmployeeId” to be copied the “Id” property, when the mapping happens. Here’s the code:

// Original standard "create map" statement...
Mapper.CreateMap<Controllers.EmployeeBase, Controllers.EmployeeWithLink>();

// New statement, which projects the value of EmployeeId into Id
Mapper.CreateMap<Controllers.EmployeeBase, Controllers.EmployeeWithLink>()
    .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.EmployeeId));

 

Incidentally…

If you wanted to re-design your resource model classes to avoid using composed names for the identifier properties, you could use projection. This is a clean way to have all your resource model class identifiers with “Id” names.

 

Update the object constructors
Wrap the fetch result(s) in a resource model class that includes link relations,
and configure the links

Our goal is to “wrap” the result(s) in the new resource 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 “otem” to each item
  6. Return the now-full-configured object

 

Study the LinkRelationsIntro code example.

 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

 

Advertisements
%d bloggers like this: