ramires.cabral ramires.cabral - 21 days ago 5
reST (reStructuredText) Question

Proper approach to create hypermedia in c# webapi

I'm doing some research on how to implement hypermedia for a particular resource, but can't find a real implementation example, just abstractions...

You know, in various articles, the guy create a method like:

public List<Link> CreateLinks(int id)
{
...//Here the guy put these three dots, whyyyyyyyyyy?
}


What I have so far:

public Appointment Post(Appointment appointment)
{
//for sake of simplicity, just returning same appointment
appointment = new Appointment{
Date = DateTime.Now,
Doctor = "Dr. Who",
Slot = 1234,
HyperMedia = new List<HyperMedia>
{
new HyperMedia{ Href = "/slot/1234", Rel = "delete" },
new HyperMedia{ Href = "/slot/1234", Rel = "put" },
}
};

return appointment;
}


And the Appointment class:

public class Appointment
{
[JsonProperty("doctor")]
public string Doctor { get; set; }

[JsonProperty("slot")]
public int Slot { get; set; }
[JsonProperty("date")]
public DateTime Date { get; set; }

[JsonProperty("links")]
public List<HyperMedia> HyperMedia { get; set; }
}

public class HyperMedia
{
[JsonProperty("rel")]
public string Rel { get; set; }

[JsonProperty("href")]
public string Href { get; set; }
}


Is there a proper way to that? I mean, without hard coding the links? How to create them dynamically for a given type, i.e. Appointment class?

I'm using c# Webapi, not c# MVC.

Answer
  1. For adding routes dynamically to the HyperMedia collection you can make use of route naming:

    • Define your route with a specific name (for example for deletion):

      [Route("{id:int}", Name = "AppointmentDeletion")]
      public IHttpActionResult Delete(int slot)
      {
          //your code
      }
      
    • Use it by UrlHelper.Link method:

      public Appointment Post(Appointment appointment)
      {
          appointment = new Appointment
          {
              HyperMedia = new List<HyperMedia>
              {
                  new HyperMedia
                  { 
                      Href = Url.Link("AppointmentDeletion", new { slot = 1234 }), 
                      Rel = "delete" 
                  }
              }
      
          return appointment;
      }; 
      
  2. It is also possible to add links dynamically to a result object without declaring the HyperMedia property for every class:

    • Define a class without links:

      public class Appointment
      {
          [JsonProperty("doctor")]
          public string Doctor { get; set; }
      
          [JsonProperty("slot")]
          public int Slot { get; set; }
      
          [JsonProperty("date")]
          public DateTime Date { get; set; }
      } 
      
    • Define an extension method:

      public static class LinkExtensions
      {
          public static dynamic AddLinks<T>(this T content, params object[] links)
          {
              IDictionary<string, object> result = new ExpandoObject();
      
              typeof (T)
                  .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                  .ToList()
                  .ForEach(_ => result[_.Name.ToLower()] = _.GetValue(content));
      
              result["links"] = links;
      
              return result;
          }
      }
      
    • Use it:

      public IHttpActionResult Post(Appointment appointment)
      {
          return Ok(appointment.AddLinks(new HyperMedia
          { 
              Href = Url.Link("AppointmentDeletion", new { slot = 1234 }), 
              Rel = "delete" 
          }));
      }