Creating RESTful Web Services with ASP.NET Web API

  1. RESTful web services
    1. REpresentational State Transfer
      1. A service represents a resource that you can access from the web
      2. Commonly makes use of different HTTP request methods to implement CRUD functions:
        1. POSTCreate new resource
        2. GETRetrieve resource
        3. PUTUpdate resource
        4. DELETEDelete resource
      3. Also makes use of other HTTP mechanisms: the query string, path info, etc.
      4. Requests are stateless; you do not have a session
  2. Creating an ASP.NET Web API
    1. Create a new project in Visual Studio
    2. Select project type ASP.NET MVC 4 Web Application
    3. Name the project StudentWebService and press OK
    4. Select the Web API project type and press OK
    5. Creating the Model
      1. The data model uses is composed of classes with public properties that will be transformed into JSON or XML when transmitted by the web service
      2. Right-click Models folder, Add → Class...
      3. Name the file Student.cs and click Add button
      4. Create Student class with public properties
        public class Student
        {
        	public int Id { get; set; }
        	public string Name { get; set; }
        	public float Gpa { get; set; }
        }				
        
      5. Add another class to Models called StudentRepository that implements CRUD operations on the list of students
        public class StudentRepository
        {
        	// List of students
        	private List<Student> students = new List<Student>(new Student[]
        		{
        			new Student { Id = 1, Name = "Bob Smith", Gpa = 2.5f },
                    new Student { Id = 2, Name = "Sue White", Gpa = 3.0f }
        		});
        
        	public List<Student> GetAllStudents()
        	{
        		return students;
        	}
        
        	public Student GetStudent(int id)
        	{
        		// Return back garbage student if the ID was not found
        		var student = students.FirstOrDefault(p => p.Id == id);
        		if (student == null)
        			return new Student { Id = -1, Name = "NULL" };
        
        		return student;
        	}
        
        	public bool AddStudent(Student student)
        	{
        		if (student == null)
        			throw new ArgumentNullException("student");
                    
        		// Make sure student ID is unique
        		var findStudent = students.FirstOrDefault(p => p.Id == student.Id);
        		if (findStudent == null)
        		{
        			students.Add(student);
        			return true;
        		}
        			
        		return false;
        	}
        
        	public bool UpdateStudent(Student student)
        	{
        		// See if a student with this ID exists so he can be replaced
        		int i = students.FindIndex(p => p.Id == student.Id);
        		if (i == -1)
        			return false;
        
        		students[i] = student;
        		return true;
        	}
        
        	public bool DeleteStudent(int stuId)
        	{
        		// See if a student with this ID exists so he can be deleted
        		int i = students.FindIndex(p => p.Id == stuId);
        		if (i == -1)
        			return false;
        
        		students.RemoveAt(i);
        		return true;
        	}
        }			
        
    6. Creating API Controllers
      1. Controllers implement the GET, POST, UPDATE, and DELETE http methods
      2. Each function corresponding to verbs must start with Get, Post, Update, and Delete
      3. Right-click Controllers folder, Add → Controller...
      4. Give controller name StudentController, select Empty API Controller from the Template menu, and press Add button
      5. Add using statement
        using StudentWebService.Models;
        
      6. Add code that implements CRUD operations and uses the StudentRepository to manipulate the model
        public class StudentController : ApiController
        {
        	private static StudentRepository studentRepo = new StudentRepository();
        
        	// GET api/student
        	public IEnumerable<Student> GetAll()
        	{
        		return studentRepo.GetAllStudents();
        	}
        
        	// GET api/student/2
        	public Student Get(int id)
        	{
        		var student = studentRepo.GetStudent(id);
        		if (student == null)
        			throw new HttpResponseException(HttpStatusCode.NotFound);
        		else
        			return student;
        	}
        
        	// POST api/student
        	public void Post(Student student)
        	{
        		if (!studentRepo.AddStudent(student))
        			throw new HttpResponseException(HttpStatusCode.NotFound);
        	}
        
        	// PUT api/student
        	public void Put(Student student)
        	{
        		if (!studentRepo.UpdateStudent(student))
        			throw new HttpResponseException(HttpStatusCode.NotFound);
        	}
        
        	// DELETE api/student/2
        	public void Delete(int id)
        	{
        		if (!studentRepo.DeleteStudent(id))
        			throw new HttpResponseException(HttpStatusCode.NotFound);
        	}
        }
        
  3. Accessing the API in a web browser
    1. Run the VB project and use the following URL to list all students:
      http://localhost:port/api/student
      
      On IE returns JSON:
      [[{"Id":1,"Name":"Bob Smith","Gpa":2.5},{"Id":2,"Name":"Sue White","Gpa":3.0}]
      
      In Chrome returns XML:
      <ArrayOfStudent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
      	xmlns="http://schemas.datacontract.org/2004/07/StudentWebService.Models">
         <Student>
            <Gpa>2.5</Gpa>
            <Id>1</Id>
            <Name>Bob Smith</Name>
         </Student>
         <Student>
            <Gpa>3</Gpa>
            <Id>2</Id>
            <Name>Sue White</Name>
         </Student>
      </ArrayOfStudent>
      
    2. Access single student
      http://localhost:port/api/student/2
      
      returns
      [{"Id":2,"Name":"Sue White","Gpa":3.0}]
      
    3. Chrome gets XML instead of JSON because it uses content negotiation when requesting data from the server
      1. Accept header requests application/xml with a higher weight (q=0.9) than application/json (*/* with q=0.8)
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
        
      2. IE uses the following Accept header which gives XML and JSON equal weights
        Accept: text/html, application/xhtml+xml, */*
        
    4. Use Postman add-on for Chrome or curl to issue other requests