1

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.

Alexandru Marculescu
  • 5,569
  • 6
  • 34
  • 50
ramires.cabral
  • 910
  • 4
  • 13
  • 28

2 Answers2

2
  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" 
          }));
      }
      
Andriy Tolstoy
  • 5,690
  • 2
  • 31
  • 30
1

You can definitely extract the Rel into an Enum (2 in fact, a Standard one - Delete, Put etc - and a custom one - the latter could contain custom relationships like customer-by-id).

You can also build the Href params dynamically (pull the parameters from the object's properties), but as for the resource itself...you're probably stuck with hardcoding that (you could also look into reflection).

Alexandru Marculescu
  • 5,569
  • 6
  • 34
  • 50