Search code examples
asp.net-web-apihateoashalhypermedia

How to get associated name of linked resources in HAL


I am creating an API for project tasks. It has a TasksController as listed below. I am generating hypermedia using WebApi.Hal and the service supports hal+json and hal+xml media types also.

Following is the response I currently have for the GET request http://localhost:51910/api/tasks/1. In the response there is a list of links for priorities – but they don’t have associated name in the response (to show in the UI – like Low, Medium, High, etc.).

What is the best HAL approach for getting name of the priorities also, using WebApi.HAL?

Note: The list of priorities can be enhanced in the future.

enter image description here

Priority

public class Priority
{
    public int PriorityID { get; set; }
    public string PriorityName { get; set; }
    public string Revision { get; set; }
    public DateTime ApprovalDate { get; set; }
}

Controller

public class TasksController : ApiController
    {
        // GET api/values/5
         [HttpGet]
        public TaskRepresentation Get(int id)
        {

            Task selectedTask = TasksHelper.GetTask(id);
            TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
            return taskRepresentation;
        }

        //PUT For Setting Priority
        [HttpPut]
        [Route("api/tasks/{taskID}/priorities/{priorityID}")]
        public TaskRepresentation PutSetPriority(int taskID, int priorityID)
        {
            Task selectedTask = TasksHelper.GetTask(taskID);

            Priority selectedPriority = null;
            List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
            foreach (Priority p in allPriorities)
            {
                if (p.PriorityID == priorityID)
                {
                    selectedPriority = p;
                }
            }

            //Update Task
            if (selectedPriority != null)
            {
                selectedTask.CurrentPriority = selectedPriority.PriorityName;
            }
            else
            {

                throw new Exception("Not available");
            }


            TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
            return taskRepresentation;
        }

        [HttpGet]
        [Route("api/tasks/{taskID}/priorities/{priorityID}")]
        public Priority Get(int taskID, int priorityID)
        {
            Priority selectedPriority = null;
            List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
            foreach (Priority p in allPriorities)
            {
                if (p.PriorityID == priorityID)
                {
                    selectedPriority = p;
                }
            }

            return selectedPriority;
        }

    }

HAL Generation Related Classes

public static class LinkTemplates
    {

        public static class TaskLinks
        {
            public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
            public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
        }
    }

public class TaskRepresentation : Representation
    {
        Task theTask;

        public int TaskID{get{return theTask.TaskID;}}
        public string TaskName{get{return theTask.Name;}}
        public string CurrentPriority{get{return theTask.CurrentPriority;}}
        public string Category{get{return theTask.Category;}}

        public TaskRepresentation(Task t)
        {
            theTask = t;
        }


        public override string Rel
        {
            get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
            set { }
        }

        public override string Href
        {
            get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
            set { }
        }


        protected override void CreateHypermedia()
        {
            foreach (Priority p in theTask.PossiblePriorities)
            {
                Links.Add(LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID }));
            }
        }
    }

Solution

  • HAL Specification mentions title - this will meet the requirement.

    Following is the updated response.

    {
      "TaskID": 1,
      "TaskName": "Task1",
      "CurrentPriority": "Medium",
      "Category": "IT",
      "_links": {
        "self": {
          "href": "/api/tasks/1"
        },
        "priorities": [
          {
            "href": "/api/tasks/1/priorities/101",
            "title": "Low"
          },
          {
            "href": "/api/tasks/1/priorities/103",
            "title": "High"
          },
          {
            "href": "/api/tasks/1/priorities/104",
            "title": "Critical"
          }
        ]
      }
    }
    

    WebAPI.HAL changes

    protected override void CreateHypermedia()
            {
                foreach (Priority p in theTask.PossiblePriorities)
                {
                    Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
                    lnk.Title = p.PriorityName;
                    Links.Add(lnk);
                }
            }
    

    Code

    public static class LinkTemplates
        {
    
            public static class TaskLinks
            {
                public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
                //public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
                public static Link PriorityLink 
                { 
                    get 
                    {
                        Link l = new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}");
                        return l;
                    } 
                }
            }
        }
    
    
        public class TasksController : ApiController
        {
            // GET api/values/5
             [HttpGet]
            public TaskRepresentation Get(int id)
            {
    
                Task selectedTask = TasksHelper.GetTask(id);
                TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
                return taskRepresentation;
            }
    
            //PUT For Setting Priority
            [HttpPut]
            [Route("api/tasks/{taskID}/priorities/{priorityID}")]
            public TaskRepresentation PutSetPriority(int taskID, int priorityID)
            {
                Task selectedTask = TasksHelper.GetTask(taskID);
    
                Priority selectedPriority = null;
                List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
                foreach (Priority p in allPriorities)
                {
                    if (p.PriorityID == priorityID)
                    {
                        selectedPriority = p;
                    }
                }
    
                //Update Task
                if (selectedPriority != null)
                {
                    selectedTask.CurrentPriority = selectedPriority.PriorityName;
                }
                else
                {
    
                    throw new Exception("Not available");
                }
    
    
                TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
                return taskRepresentation;
            }
    
            [HttpGet]
            [Route("api/tasks/{taskID}/priorities/{priorityID}")]
            public Priority Get(int taskID, int priorityID)
            {
                Priority selectedPriority = null;
                List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
                foreach (Priority p in allPriorities)
                {
                    if (p.PriorityID == priorityID)
                    {
                        selectedPriority = p;
                    }
                }
    
                return selectedPriority;
            }
    
        }
    
        public class TaskRepresentation : Representation
        {
            Task theTask;
    
            public int TaskID{get{return theTask.TaskID;}}
            public string TaskName{get{return theTask.Name;}}
            public string CurrentPriority{get{return theTask.CurrentPriority;}}
            public string Category{get{return theTask.Category;}}
    
            public TaskRepresentation(Task t)
            {
                theTask = t;
            }
    
    
            public override string Rel
            {
                get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
                set { }
            }
    
            public override string Href
            {
                get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
                set { }
            }
    
    
            protected override void CreateHypermedia()
            {
                foreach (Priority p in theTask.PossiblePriorities)
                {
                    Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
                    lnk.Title = p.PriorityName;
                    Links.Add(lnk);
                }
            }
        }
    
        public class Task
        {
            public string Name { get; set; }
            public int TaskID { get; set; }
            public string Category { get; set; }
            public string CurrentPriority  { get; set; }
            public List<Priority> PossiblePriorities { get; set; }
        }
        public class Priority
        {
            public int PriorityID { get; set; }
            public string PriorityName { get; set; }
            public string Revision { get; set; }
            public DateTime ApprovalDate { get; set; }
        }
    
        public static class TasksPrioritiesHelper
        {
    
            public static List<Priority> GetAllPriorities()
            {
                List<Priority> possiblePriorities = new List<Priority>();
                Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
                Priority pMedium = new Priority { PriorityID = 102, PriorityName = "Medium" };
                Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
                Priority pCritical = new Priority { PriorityID = 104, PriorityName = "Critical" };
    
                possiblePriorities.Add(pLow);
                possiblePriorities.Add(pMedium);
                possiblePriorities.Add(pHigh);
                possiblePriorities.Add(pCritical);
    
                return possiblePriorities;
            }
    
            public static List<Priority> GetAdministrativePriorities()
            {
                List<Priority> possiblePriorities = new List<Priority>();
                Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
                Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
    
                possiblePriorities.Add(pLow);
                possiblePriorities.Add(pHigh);
    
                return possiblePriorities;
            }
    
    
            public static List<Priority> GetPossiblePrioritiesForTask(Task t)
            {
                List<Priority> possibleTaskPriorities = new List<Priority>();
    
    
                if (String.Equals(t.Category, "IT"))
                {
                    possibleTaskPriorities = GetAllPriorities();
                }
                else
                {
                    possibleTaskPriorities = GetAdministrativePriorities();
                }
    
                Priority currentTaskPriority = null;
                foreach(Priority p in possibleTaskPriorities )
                {
                    if(String.Equals(t.CurrentPriority,p.PriorityName ))
                    {
                        currentTaskPriority=p;
                    }
                }
    
                if(currentTaskPriority!=null)
                {
                    possibleTaskPriorities.Remove(currentTaskPriority);
                }
    
    
                return possibleTaskPriorities;
            }
    
    
        }
        public static class TasksHelper
        {
            public static Task GetTask(int id)
            {
                Task selectedTask = null;
                List<Task> tasks = GetAllTasks();
    
                foreach (Task t in tasks)
                { 
                    if(t.TaskID==id)
                    {
                        selectedTask = t;
                    }
                }
                return selectedTask;
            }
    
    
            public static List<Task> GetAllTasks()
            {
    
                List<Task> tasks;
                tasks = new List<Task>();
    
                Task t1 = new Task{Category = "IT",CurrentPriority = "Medium",Name = "Task1",TaskID = 1};
                t1.PossiblePriorities = TasksPrioritiesHelper.GetPossiblePrioritiesForTask(t1);
    
                tasks.Add(t1);
    
                return tasks;
            }
    
    
        }