Skip to content

Jimmy Bogard
Syndicate content
Strong opinions, weakly held
Updated: 54 min 35 sec ago

NDC talk on SOLID in slices not layers video online

Thu, 07/02/2015 - 20:21

The talk I gave at NDC Oslo 2015 is up on SOLID architecture in slices not layers:

https://vimeo.com/131633177

In it I talk about flipping this style architecture:

To one that focuses on vertical deliverable features:

Enjoy!

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

End-to-end Hypermedia: Building a React Client

Wed, 07/01/2015 - 18:06

In the last post, I walked through what is to me the most interesting part of REST – the client. It’s easy to build a server API, but no API is complete without someone actually using that API. This is where most REST examples fall down for me – they show all sorts of pretty pictures of hypermedia-rich JSON from the server, but no real examples of how to consume that API.

I walked through some jQuery code in the last post, but why stop with jQuery? That’s so 2010. Instead, I want to build around React. React is perfect for hypermedia because of its component-oriented nature. A resource’s representation can be broken down into its components, and React components then matched accordingly. But before we get into the client, I’ll need to modify my sample to consume React.

Installing React

As a shortcut, I’m just going to use ReactJS.Net to build React into my existing MVC app. I install the ReactJS.Net NuGet package, and add a script reference to my downloaded react.js library. Normally, I’d go through the whole Bower/npm path, but this seemed like the simplest path to integrate into my sample.

I’m going to create just a blank JSX file for all my React components for this page, and slim down my Index view to the basics:

<h2>Instructors</h2>
<div id="content"></div>
@section scripts{
    <script src="@Url.Content("~/Scripts/react-0.13.3.js")"></script>
    <script src="@Url.Content("~/Scripts/InstructorInfo.jsx")"></script>
    @{
        var href = Url.Action("Index", "Instructor", new {httproute = ""});
    }
    <script>
        React.render(
            React.createElement(InstructorsInfo, {href: '@href'}),
            document.getElementById("content")
        );
    </script>
}

All of the div placeholders are removed except one, for content. I pull in the React library and my custom React components. The ReactJS.Net package takes my JSX file and transpiles it into Javascript (as well as builds the needed files for in-browser debugging). Finally, I render my base React component, passing in the root URL for kicking off the initial request for instructors, and the DOM element in which to render the React component into.

Once I’ve got the basic React library up and running, it’s time to figure out how we would like to componentize our page.

Slicing our Page

If we look at the page we want to create, we need to take this page and create React components from the parts we find. Here’s our page from before:

Looking at this, I see three individual tables populated with collection+json data. I’m thinking I create one overall component composed of three individual items. Inside the table, I can break things up into the table, rows, header, cells and links:

I might need a few more, but this is a good start. Next, we can start building our React components.

React Components

First up is our overall component that contains our three tables of collection+json data. Since I have an understanding of what’s getting returned on the server side, I’m going to make an assumption that I’m building out three tables, and I can navigate links to drill down to more. Additionally, this component will be responsible for making the initial AJAX call and keeping the overall state. State is important in React, and I’ve decided to keep the parent component responsible for the resource state rather than each table. My InstructorInfo component is:

class InstructorsInfo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      instructors: { },
      courses: { },
      students: { }
    };
    this._handleSelect = this._handleSelect.bind(this);
  }
  componentDidMount() {
    $.getJSON(this.props.href)
      .done(data => this.setState({ instructors: data }));
  }
  _handleSelect(e) {
    $.getJSON(e.href)
      .done(data => {
        var state = e.rel === "courses"
          ? { students: {}}
          : {};

        state[e.rel] = data;

        this.setState(state);
      });
  }
  render() {
    return (
      <div>
        <CollectionJsonTable data={this.state.instructors}
          onSelect={this._handleSelect} />
        <CollectionJsonTable data={this.state.courses}
          onSelect={this._handleSelect} />
        <CollectionJsonTable data={this.state.students}
          onSelect={this._handleSelect} />
      </div>
    )
  }
}

I’m using ES6 here, which makes building React components a bit nicer to work with. I first declare my React component, extending from React.Component. Next, in my constructor, I set up the initial state, a object with empty values for the instructors/courses/students state. Finally, I set up the binding for a callback function to bind to the React component as opposed to the function itself.

In the componentDidMount function, I perform the initial AJAX call and set the instructors collection state based on the data that gets back. The URL I use to make the initial call is based on the “href” of my components properties.

The _handleSelect function is the callback of the clicked link way down on one of the tables. I wanted to have the parent component manage fetching new collections instead of a child component figuring out what to do. That method makes the AJAX call based on the “href” passed in from the collection+json data, gets the state back and updates the relevant state based on the “rel” of the link. To make things easy, I matched up the state’s property names to the rel’s I knew about.

Finally, the render function just has a div with my three CollectionJsonTable components, binding up the data and select functions. Let’s look at that component next:

class CollectionJsonTable extends React.Component {
  render() {
    if (!this.props.data.collection) {
      return <div></div>;
    }
    if (!this.props.data.collection.items.length){
      return <p>No items found.</p>;
    }

    var containsLinks = _(this.props.data.collection.items)
      .some(item => item.links && item.links.length);

    var rows = _(this.props.data.collection.items)
      .map((item, idx) => <CollectionJsonTableRow
        item={item}
        containsLinks={containsLinks}
        onSelect={this.props.onSelect}
        key={idx}
        />)
      .value();

    return (
      <table className="table">
        <CollectionJsonTableHeader
          data={this.props.data.collection.items}
          containsLinks={containsLinks} />
        <tbody>
          {rows}
        </tbody>
      </table>
    );
  }
}

This one is not quite as interesting. It only has the render method, and the first part is just to manage either no data or empty data. Since my data can conditionally have links, I found it easier to inform child components whether or not links exist (through the lodash code), rather than every component having to re-figure this out.

To build up each row, I map the collection+json items to CollectionJsonTableRow components, setting up the necessary props (the item, containsLinks, onSelect and key items). In React, there’s no event aggregator so I have to pass down a callback function to the lowest component via properties all the way down. Finally, since I’m building a collection of components, it’s best practice to put some sort of key on these items so that React knows how to re-render correctly.

The final rendered component is a table with a CollectionJsonTableHeader and the rows. Let’s look at that header next:

class CollectionJsonTableHeader extends React.Component {
  render() {
    var headerCells = _(this.props.data[0].data)
      .map((datum, idx) => <th key={idx}>{datum.prompt}</th>)
      .value();

    if (this.props.containsLinks) {
      headerCells.push(<th key="links"></th>);
    }

    return (
      <thead>
        <tr>
          {headerCells}
        </tr>
      </thead>
    );
  }
}

This component also only has a render method. I map the data items from the first item in the collection, producing header cells based on the prompt from the collection+json data. If the collection contains links, I’ll add an empty header cell on the end. Finally, I render the header with the header cells in a row.

With the header done, I can circle back to the CollectionJsonTableRow:

class CollectionJsonTableRow extends React.Component {
  render() {
    var dataCells = _(this.props.item.data)
      .map((datum, idx) => <td key={idx}>{datum.value}</td>)
      .value();

    if (this.props.containsLinks) {
      dataCells.push(<CollectionJsonTableLinkCell
        key="links"
        links={this.props.item.links}
        onSelect={this.props.onSelect} />);
    }

    return (
      <tr>
        {dataCells}
      </tr>
    );
  }
}

The row’s responsibility is just to build up the collection of cells, plus the optional CollectionJsonTableLinkCell. As before, I have to pass down the callback for the link clicks. Similar to the header cells, I fill in the data value (instead of the prompt). Next up is our link cell:

class CollectionJsonTableLinkCell extends React.Component {
  render() {
    var links = _(this.props.links)
      .map((link, idx) => <CollectionJsonTableLink
        key={idx}
        link={link}
        onSelect={this.props.onSelect} />)
      .value();

    return (
      <td>{links}</td>
    );
  }
}

This one isn’t so interesting, it just loops through the links, building out a CollectionJsonTableLink component, filling in the link object, key, and callback. Finally, our CollectionJsonTableLink component:

class CollectionJsonTableLink extends React.Component {
  constructor(props) {
    super(props);
    this._handleClick = this._handleClick.bind(this);
  }
  _handleClick(e) {
    e.preventDefault();
    this.props.onSelect({
      href : this.props.link.href,
      rel: this.props.link.rel}
    );
  }
  render() {
    return (
      <a href='#' rel={this.props.link.rel} onClick={this._handleClick}>
        {this.props.link.prompt}
      </a>
    );
  }
}
CollectionJsonTableLink.propTypes = {
  onSelect: React.PropTypes.func.isRequired
};

The link clicks are the most interesting part here. I didn’t want my link itself to have the behavior of what to do on click, so I call my “onSelect” prop in the click event from my link. The _handleClick method calls the onSelect method, passing in the href/rel from the collection+json link object. In my render method, I just output a normal anchor tag, with the rel and prompt from the link object, and the onClick event bound to the _handleClick method. Finally, I indicate that the onSelect prop is required, so that I don’t have to check for its existence when the link is clicked.

With all these components, I’ve got a working example:

I found working with hypermedia and React to be a far nicer experience than just raw jQuery. I could reason about individual components at the same level as the hypermedia controls, matching what I was building much more effectively to the resource representation returned. I still have to have some sort of knowledge of how I’m going to navigate the links and what to do, but that logic is all encapsulated in my topmost component.

Each of the sub-components aren’t tied to my overall logic and can be re-used as much as I want across my application, allowing me to use collection+json extensively and not worry about having to parse the result again and again. I’ve got a component that can effectively render a nice table based on a collection+json representation.

Next, we’ll kick things up a notch and build out a React.Native implementation, pushing the limit of hypermedia with a dynamic native mobile client.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

End-to-End Hypermedia: Building the Client

Thu, 06/18/2015 - 14:41

Now that we’ve built our hypermedia-rich server component, we can focus now on the client portion. Building the server piece, while somewhat involved, isn’t too much different than building a plain JSON API. We had to build a piece to translate our model to a richer hypermedia model, but I don’t see this as much different than what I have to do with views/templates.

The client is a completely different story. My payloads coming back from the server have a lot of metadata in them, and in order to achieve the loose coupling that REST can provide, my clients have to be driven off of that metadata.

Ultimately, my clients can’t be completely agnostic of what we’re doing on the server. A general-purpose client for a standard hypermedia format will look generic and boring. We’re not trying to build a generic client, we’re building one for a specific purpose.

In my case, I’d like to build a basic navigable details screen. Show a table of information, and supply links to drill down into further details.

First, I’ll need to have some understanding of what the server response looks like. I know I’ll have a list of instructors, then a list of courses, then a list of students attending those courses. Each of these will be a table, but I want a place to put that table on the screen. For this, I’ll create divs with IDs that match the RELs of the links in my collection+json response:

<div id="instructors"></div>
<div id="courses"></div>
<div id="students"></div>

When the page loads, I want to kick off the rendering with an initial request:

$(function () {
    fetchCollection('/instructors', 'instructors');
});

Nothing much going on here, I just call a method “fetchCollection”. I pass in the initial URL to hit, and the ID of DIV. The fetchCollection method:

var fetchCollection = function(relativeUrl, target) {
    $.getJSON(root + relativeUrl)
        .done(function (data) {
            renderCollectionJsonTable(data, target);
        })
        .fail(function (jqxhr, textStatus, error) {
            var err = textStatus + ", " + error;
            console.log("Request Failed: " + err);
        });
};

Will make a call to the API, return the result and render the result to the target DIV via the “renderCollectionJsonTable” method:

var renderCollectionJsonTable = function(data, target) {
    var $target = $('#' + target);
    $target.html('');

    var $table = $('<table>').addClass('table');
    var hasAddedHeader = false;
    var hasLinks = false;

    $.each(data.collection.items, function (idx, item) {

        if (item.links) {
            hasLinks = true;
        }

        if (!hasAddedHeader) {
            var $headerRow = $('<tr>');
            $.each(item.data, function(idx2, datum) {
                $('<th>').text(datum.prompt).appendTo($headerRow);
            });
            if (hasLinks) {
                $('<th>').appendTo($headerRow);
            }
            $headerRow.appendTo($table);
            hasAddedHeader = true;
        }

        var row = $('<tr>');
        $.each(item.data, function (idx2, datum) {
            var $cell = $('<td>');
            if (datum.value) {
                $cell.text(datum.value);
            }
            $cell.appendTo(row);
        });

        if (hasLinks) {
            var $linkCell = $('<td>');
            $.each(item.links, function (idx2, link) {
                var $link = $('<a>').attr('rel', link.rel).attr('href', '#').text(link.prompt + ' ');
                $link.click(function () {
                    fetchCollection(link.href, link.rel);
                    return false;
                });
                $link.appendTo($linkCell);
            });
            $linkCell.appendTo(row);
        }

        row.appendTo($table);
    });

    $table.appendTo($target);
};

This method is…quite involved. We’re trying to render a table, including the header and links. To render the header, I loop through the collection+json data elements and pluck off the prompt for the header text. If the data elements have links, then I render an extra column at the end.

I only render the header once, and since collection+json includes prompt information for every single element in the collection every single time, I have to just pluck off the first item in the collection and render the header row for it (assuming the prompts don’t change).

For rendering the actual data row, it’s pretty straightforward to loop through the data items and render the data portion for each one. Finally, if the item has links, I’ll render all the links together, using the link prompt and rel to indicate where to place the linked data on the screen.

The method to render a table of collection+json data is relatively decoupled from what the collection+data represents. The only real app-specific piece is how to navigate the collections and what to do in each case (render results in a new DIV).

Rendering the table was rather too involved for my taste, and I’d like to componentize it if I can. In the last post, I’ll look at using ReactJS to build React components for the different rendering pieces in the table.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

End-to-End Hypermedia: Building the Server

Wed, 06/03/2015 - 19:26

In the last post, we looked at choosing a hypermedia type. This isn’t the easiest of things to do, and can take quite a bit of effort to settle on a choice. On top of that, you very often need validation from a client consumer that your choice was correct. Unfortunately, even tools like Apiary.io aren’t sufficient, you really need to build your API to validate your API.

This isn’t completely unexpected. If I’m building any sort of software the only way of proving it is what I need is to actually use it.

In our case, we choose collection+json as our media type since we were mainly showing lists of things. It’s a fairly straightforward format, with out of the box support for ASP.NET Web API. There are a few NuGet packages that help with collection+json support:

  • CollectionJson.Server – includes a base controller class
  • CollectionJson.Client – includes a formatter
  • CollectionJson – just the object model with no dependencies

We first explored using these out-of-the-box, with the controller base class Server version:

public class FriendsController : CollectionJsonController<Friend>
{
    private IFriendRepository repo;

    public FriendsController(IFriendRepository repo, ICollectionJsonDocumentWriter<Friend> writer, ICollectionJsonDocumentReader<Friend> reader)
        :base(writer, reader)
    {
        this.repo = repo;
    }

    protected override int Create(IWriteDocument writeDocument, HttpResponseMessage response)
    {
        var friend = Reader.Read(writeDocument);
        return repo.Add(friend);
    }

    protected override IReadDocument Read(HttpResponseMessage response)
    {
        var readDoc = Writer.Write(repo.GetAll());
        return readDoc;
    }

    protected override IReadDocument Read(int id, HttpResponseMessage response)
    {
        return Writer.Write(repo.Get(id));
    }

    //custom search method   
    public HttpResponseMessage Get(string name)
    {
        var friends = repo.GetAll().Where(f => f.FullName.IndexOf(name, StringComparison.OrdinalIgnoreCase) > -1);
        var readDocument = Writer.Write(friends);
        return readDocument.ToHttpResponseMessage();
    }

    protected override IReadDocument Update(int id, IWriteDocument writeDocument, HttpResponseMessage response)
    {
        var friend = Reader.Read(writeDocument);
        friend.Id = id;
        repo.Update(friend);
        return Writer.Write(friend);
    }

    protected override void Delete(int id, HttpResponseMessage response)
    {
        repo.Remove(id);
    }
}

If we were implementing a very pure version of collection+json, this might be a good route. However, not all of the HTTP methods were supported for our operations, so we wound up not using this one.

Next, we looked at the Client package, which includes a formatter and some extensions around HttpResponseMessages and the like. That worked best for us – we didn’t really need to extend the model to support extra metadata. I had thought we did, but looking back, we went through several iterations and finally landed on the stock collection+json model.

When looking at Web API extensions for hypermedia, I tend to see three sets of extensions:

  • Object model that represents the media type and is easily serializable
  • Helpers for inside your controller
  • Base controller classes

The code inside of these isn’t that much, so you can always just grab code from GitHub for your media type or roll your own object models.

Building your models

The CollectionJson.Client package deals with two-way model building – writing documents and reading documents. Writing a document involves taking a DTO and building a collection+json document. Reading a document involves taking a collection+json document and building a model.

In my plain ol’ JSON APIs, building a web API endpoint looks almost exactly like an MVC one:

public class FooController : ApiController
{
    private readonly IMediator _mediator;

    public OrganizationController(IMediator mediator)
    {
        _mediator = mediator;
    }

    public IEnumerable<FooModel> Get()
    {
        return _mediator.Send(new FooQuery());
    }

    public IEnumerable<FooModel> Get(string id)
    {
        return _mediator.Send(new FooQuery{Id = id});
    }
}

With building out documents, I need to take those DTOs and build out my representations  (my collection+json documents). The collection+json client defines two interfaces to help make this possible:

public interface ICollectionJsonDocumentReader<TItem>
{
    TItem Read(IWriteDocument document);
}
public interface ICollectionJsonDocumentWriter<TItem>
{
    IReadDocument Write(IEnumerable<TItem> data);
}

To make my life a bit easier, I created a mediator just for collection+json readers/writers, as I like to have a single point in which to request read/write documents:

public interface ICollectionJsonDocumentMediator
{
    IReadDocument Write<TItem>(TItem item);
    IReadDocument Write<TItem>(IEnumerable<TItem> item);
    TItem Read<TItem>(IWriteDocument document);
}

Once again we see that the Mediator pattern is great for turning types with generic parameters into methods with generic parameters. Our mediator implementation is pretty straightforward:

public class CollectionJsonDocumentMediator : ICollectionJsonDocumentMediator {
    private readonly IContainer _container;

    public CollectionJsonDocumentMediator(IContainer container) {
        _container = container;
    }

    public IReadDocument Write<TItem>(IEnumerable<TItem> item) {
        var writer = _container.GetInstance<ICollectionJsonDocumentWriter<TItem>>();

        return writer.Write(model);
    }
    
    public IReadDocument Write<TItem>(TItem item) {
        var writer = _container.GetInstance<ICollectionJsonDocumentWriter<TItem>>();

        return writer.Write(model);
    }
    
    public TItem Read<TItem<(IWriteDocument writeDocument) {
        var reader = _container.GetInstance<ICollectionJsonDocumentReader<TItem>>();

        return reader.Read(writeDocument);
    }
}

In our controllers, building out the responses is fairly easy now, we just add a step before our MediatR mediator:

public class InstructorController : ApiController {
    private readonly IMediator _mediator;
    private readonly ICollectionJsonDocumentMediator _documentMediator;
    
    public InstructorController(
        IMediator mediator,
        ICollectionJsonDocumentMediator documentMediator) {
        _mediator = mediator;
        _documentMediator = documentMediator;
    }
    
    public async Task<HttpResponseMessage> Get([FromUri] Get.Query model) {
        var model = await _mediator.SendAsync(model);
    
        var document = _documentMediator.Write(model);
    
        return document.ToHttpResponseMessage();
    }
}

The MediatR part will be the same as we would normally have. What we’ve added is our collection+json step of taking the DTO from the MediatR step and routing this to our collection+json document mediator. The document writer is then pretty straightforward too:

public class Get {
    // Query, model and handler here
    
    public class DocumentWriter
        : ICollectionJsonDocumentWriter<Model> {
        
        private readonly HttpRequestContext _context;
        
        public DocumentWriter(HttpRequestContext context) {
            _context = context;
        }
        
        public IReadDocument Write(IEnumerable<Model> data) {
            var document = new ReadDocument {
                Collection = new Collection {
                    Href = _context.url.Link<InstructorController>(c => c.Get()),
                    Version = "1.0"
                }
            };
            
            foreach (var model in data) {
                var item = new Item {
                    Href = _context.Url.Link<InstructorController>(c => c.Get(new Query {Id = model.Id}))
                };
                item.Data.Add(new Data { Name = "last-name", Value = model.LastName, prompt = "Last Name"});
                item.Data.Add(new Data { Name = "first-name", Value = model.FirstMidName, prompt = "First Name"});
                item.Data.Add(new Data { Name = "hire-date", Value = model.HireDate.ToString("yyyy-MM-dd"), prompt = "Hire Date"});
                item.Data.Add(new Data { Name = "location", Value = model.OfficeAssignmentLocation, prompt = "Location"});
                
                item.Links.Add(new Link {
                    Href = _context.Url.Link<InstructorController>(c => c.GetCourses(new Courses.Query {Id = model.Id})),
                    Prompt = "Courses",
                    Rel = "courses"
                });
                document.Collection.Items.Add(item);
            }
            
            return document;
        }
    }
}

If you’ve followed my conventional HTML series, you might notice that the kind of information we’re putting into our collection+json document is pretty similar to the metadata we read when building out intelligent views. This helps close a gap I’ve found when building SPAs – I was much less productive building these pages than regular server-side MVC apps since I lost all that nice metadata that only lived on the server. Pre-compiling views can work, but additional metadata in hypermedia-rich media types works too.

For the write side, I could build something similar, including templates and the like. In fact, you can borrow our ideas from conventional HTML to build out helpers for our collection+json models. Since we have models built around read/write items:

public class Model
{
    public int? ID { get; set; }

    public string LastName { get; set; }
    [Display(Name = "First Name")]
    public string FirstMidName { get; set; }

    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
    public DateTime? HireDate { get; set; }

    [Display(Name = "Location")]
    public string OfficeAssignmentLocation { get; set; }
}

We can intelligently build out templates and data items:

public class Get {
    // Query, model and handler here
    
    public class DocumentWriter
        : ICollectionJsonDocumentWriter<Model> {
        
        private readonly HttpRequestContext _context;
        
        public DocumentWriter(HttpRequestContext context) {
            _context = context;
        }
        
        public IReadDocument Write(IEnumerable<Model> data) {
            var document = new ReadDocument {
                Collection = new Collection {
                    Href = _context.url.Link<InstructorController>(c => c.Get()),
                    Version = "1.0"
                }
            };
            
            foreach (var model in data) {
                var item = new Item {
                    Href = _context.Url.Link<InstructorController>(c => c.Get(new Query {Id = model.Id}))
                };
                item.Data.Add(model.ToData(m => m.LastName));
                item.Data.Add(model.ToData(m => m.FirstMidName));
                item.Data.Add(model.ToData(m => m.HireDate));
                item.Data.Add(model.ToData(m => m.OfficeAssignmentLocation));

                item.Links.Add(_context.Url.CollectionJsonLink<InstructorController>(c => c.GetCourses(new Courses.Query {Id = model.Id)));
                
                document.Collection.Items.Add(item);
            }
            document.Collection.Template.Data.BuildFrom<Post.Model>();
            
            return document;
        }
    }
}

Our document writers start to look somewhat similar to our Razor views. On the document reader side, it’s a similar exercise of pulling information out of the document, populating a DTO and sending down the MediatR pipeline. Just the reverse of our GET actions.

Altogether not too bad with the available extensions, but building the server API is just half the battle. In the next post, we’ll look at building a consuming client.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

End-to-End Hypermedia: Choosing a Media Type

Fri, 05/22/2015 - 17:12

So you’ve decided to make the leap and build a hypermedia-rich API. Hopefully, this decision came from necessity and not boredom, but that’s a post for another day.

At this point, you’re presented with a bit of a problem. You have 3 main options for choosing/designing a media type:

  • Pick a standard
  • Design your own
  • Extend a standard

As much as possible, I’d try to go with a standards-based approach. People with much more time on their hands and much more passion for you have thought about these problems for years, and probably have thought about more scenarios than you’re thinking of right now.

Instead of choosing media types in a vacuum, how would one compare the capabilities and intentions of one media type versus another? One way is simply to look at the design goals of a media type. Another is to objectively measure the level of hypermedia support and sophistication of a media type, with H Factor:

The H Factor of a media-type is a measurement of the level of hypermedia support and sophistication of a media-type. H Factor values can be used to compare and contrast media types in order to aid in selecting the proper media-type(s) for your implementation.

H-Factor looks at two types of support, links and control data, and different factors inside those.

For example, HTML supports:

  • Embedding links
  • Outbound links
  • Templated queries (a FORM with GET)
  • Non-idempotent updates (a FORM with POST)
  • Control data for update requests
  • Control data for interface methods (POST vs GET)
  • Control data for links (link relations – rel attribute)

But doesn’t support:

  • Control data for read requests – links can’t contain accept headers, for example
  • Support for idempotent updates – you have to use XHR for PUT/DELETE

With the quantitative and qualitative aspects factored in with client needs, you’ll have what you need to pick a media type. Unless you’ve already decided that this is all way too complex and run back to POJSOs, which is still perfectly acceptable.

Making the choice

There are a *ton* of popular, widely used, hypermedia-rich media types out there:

And probably a dozen others. At this point, just be warned, you’ll probably spend upwards of a week or so to decide which variant you like best based on your client’s needs. You also don’t need to decide a single media type – you can use collection+json for collections of things, and HAL for single entities if you like.

One other thing I found is no single media type had all the pieces I needed. In my real-world example, I chose collection+json because my client mainly displayed collections of things. Show a table, click an item, then display a single thing with a table of related things. It didn’t need PUT/DELETE support, or some of the other control data. I just needed control data for links and a way to distinguish queries versus forms.

But collection+json didn’t *quite* have all the things I needed, so I wound up extending it for my own purposes, which I’ll go into in the next post.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

End-to-End Hypermedia: Making the Leap

Tue, 05/19/2015 - 17:26

REST, a term that few people understand and fewer know how to implement, has become a blanket term for any sort of Web API. That’s unfortunate, because the underlying foundation of REST has a lot of benefits. So much so that I’ve started talking about regular Web APIs not as “RESTful” but just as a “Web API”. The value of REST for me has come from the hypermedia aspect of REST.

REST and hypermedia aren’t free – they significantly complicate both the building of the server API and the clients. But they are useful in certain scenarios, as I laid out in talking about the value proposition of hypermedia:

  • Native mobile apps
  • Disparate client deployments talking to a single server
  • Clients talking to disparate server deployments

I’ve only put one hypermedia-driven API into production (which, to be frank, is one more than most folks who talk about REST). I’ve attempted to build many other hypermedia APIs, only to find hypermedia was complete overkill.

If your client is deployed at the same time as your server, lives in the same source control repository, hypermedia doesn’t provide much value at all.

Hypermedia is great at decoupling client from server, allowing the client to adjust according to the server. In most apps I build, I happily couple client to server, taking advantage of the metadata I find on the server to build highly intelligent clients:

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Instructor</h4>
        <hr />
        @Html.ValidationDiv()
        @Html.FormBlock(m => m.LastName)
        @Html.FormBlock(m => m.FirstMidName)
        @Html.FormBlock(m => m.HireDate)
        @Html.FormBlock(m => m.OfficeAssignmentLocation)

In this case, my client is the browser, but my view is intelligently built up so that labels, text inputs, drop downs, checkboxes, date pickers and so on are created using metadata from a variety of sources. I can even employ this mechanism in SPAs, where my templates are pre-rendered using server metadata.

I don’t really build APIs for clients I can’t completely control, so those have completely different considerations. Building an API for public consumption means you want to enable as many clients as possible, balancing coupling with flexibility. The APIs I’ve built for clients I don’t own, I’ve never used hypermedia. It just put too much burden on my clients, so I just left it as plain old JSON objects (POJSONOs).

So if you’ve found yourself in a situation where you’ve convinced yourself you do need hypermedia, primarily based on coupling decisions, you’ll need to do a few things to get a full hypermedia solution end-to-end:

  • Choose a hypermedia-rich media type
  • Build the server API
  • Build the client consumer

In the next few posts, I’ll walk through end-to-end hypermedia from my experiences of shipping a hypermedia API server and a client consumer.

 

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs