Learn how to create a REST API with Attribute Routing in WEB API Part 4

Rama Sagar
Posted by in ASP.NET Web API category on for Beginner level | Points: 250 | Views : 5560 red flag
Rating: 4 out of 5  
 1 vote(s)

According to MSDN, Routing is how Web API matches a URI to an action. Web API 2 supports a new type of routing, called attribute routing.
In this article we will look into creating a REST API using Attribute Routing in WEB API2

Introduction


In this article, we will use attribute routing to create a REST API for a collection of products.For a general overview of attribute routing, see previous articles Part 1 ,Part 2,


Objective


The Objective of the article is to create a REST API using Attribute Routing in WEB API 2



  • Step 1  We will convert the Productscontroller to use attribute routing. First, add a RoutePrefix attribute to the controller. This attribute defines the initial URI segments for all methods on this controller.

    [RoutePrefix("api/products")]
    public class ProductsController : ApiController
    {
	//.......
    }

       Then add [Route] attributes to the controller actions, as follows

	[Route("")]
        public IQueryable GetProducts()
        {
            return db.Products.Include(b => b.Manufacturer).Select(AsProductDtO);
        }



        [Route("{id:int}")]
        [ResponseType(typeof(ProductDtO))]
        public async Task GetProduct(int id)
        {




  • Step 2 To get product details, the client will send a GET request to /api/products/{id}/details, where {id} is the ID of the product,

Add the following method to the ProductsController class.

       [Route("{id:int}/details")]
        [ResponseType(typeof(ProductDetailDto))]
        public async Task<IHttpActionResult> GetProductDetail(int id)
        {
            var product = await (from b in db.Products.Include(b => b.Manufacturer)
                                 where b.ManufacturerId == id
                                 select new ProductDetailDto
                              {
                                  Title = b.Title,
                                  Category = b.Category,
                                  ReleaseDate = b.ReleaseDate,
                                  Price = b.Price,
                                  Description = b.Description,
                                  Manufacturer = b.Manufacturer.Name
                              }).FirstOrDefaultAsync();

            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }

Now If we request /api/products/1/details, the response looks like this



  • Step 3 : To get a list of products in a specific category,the client will send a GET request to /api/products/category, where category is the name of the category. (For example, /get/products/Electronics.).
Add the following method to ProductsController.


        [Route("{genre}")]
        public IQueryable<ProductDtO> GetProductsByCategory(string category)
        {
            return db.Products.Include(b => b.Manufacturer)
                .Where(b => b.Category.Equals(category, StringComparison.OrdinalIgnoreCase))
                .Select(AsProductDtO);
        }



Here we are defining a route that contains a {category} parameter in the URI template. Notice that Web API is able to distinguish these two URIs and route them to different methods:

/api/products/1

/api/products/Electronics

That's because the GetProduct method includes a constraint that the "id" segment must be an integer value:

Here is the complete code for the ProductsController class

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using ProductsAPI.Models;
using ProductsAPI.DTOs;
using System.Linq.Expressions;

namespace ProductsAPI.Controllers
{
    
    [RoutePrefix("api/products")]
    public class ProductsController : ApiController
    {
        private ProductsAPIContext db = new ProductsAPIContext();

        // Typed lambda expression for Select() method. 
        private static readonly Expression<Func<Product, ProductDtO>> AsProductDtO =
            x => new ProductDtO
            {
                Title = x.Title,
                Manufacturer = x.Manufacturer.Name,
                Category = x.Category
            };

        // GET api/Products
        [Route("")]
        public IQueryable<ProductDtO> GetProducts()
        {
            return db.Products.Include(b => b.Manufacturer).Select(AsProductDtO);
        }

        // GET api/Products/5
        [Route("{id:int}")]
        [ResponseType(typeof(ProductDtO))]
        public async Task<IHttpActionResult> GetProduct(int id)
        {
            ProductDtO product = await db.Products.Include(b => b.Category)
                .Where(b => b.ProductId == id)
                .Select(AsProductDtO)
                .FirstOrDefaultAsync();
            if (product == null)
            {
                return NotFound();
            }

            return Ok(product);
        }

      
        [Route("{id:int}/details")]
        [ResponseType(typeof(ProductDetailDto))]
        public async Task<IHttpActionResult> GetProductDetail(int id)
        {
            var product = await (from b in db.Products.Include(b => b.Manufacturer)
                                 where b.ManufacturerId == id
                                 select new ProductDetailDto
                              {
                                  Title = b.Title,
                                  Category = b.Category,
                                  ReleaseDate = b.ReleaseDate,
                                  Price = b.Price,
                                  Description = b.Description,
                                  Manufacturer = b.Manufacturer.Name
                              }).FirstOrDefaultAsync();

            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }
        [Route("{genre}")]
        public IQueryable<ProductDtO> GetProductsByCategory(string category)
        {
            return db.Products.Include(b => b.Manufacturer)
                .Where(b => b.Category.Equals(category, StringComparison.OrdinalIgnoreCase))
                .Select(AsProductDtO);
        }
        //To get a list of a products for a particular manufacturer, the client will send a GET request to /api/manufacturers/id/products, where id is the ID of the manufacturer.


        [Route("~api/manufacturers/{manufacturerId}/products")]
        public IQueryable<ProductDtO> GetproductsByManufacturer(int manufacturerId)
        {
            return db.Products.Include(b => b.Manufacturer)
                .Where(b => b.ManufacturerId == manufacturerId)
                .Select(AsProductDtO);
        }


        //Here we restricted the route to a particular format by adding a regular-expression constraint to the route template

        [Route("date/{reldate:datetime:regex(\\d{4}-\\d{2}-\\d{2})}")]
        [Route("date/{*reldate:datetime:regex(\\d{4}/\\d{2}/\\d{2})}")]
        public IQueryable<ProductDtO> GetProducts(DateTime pubdate)
        {
            return db.Products.Include(b => b.Manufacturer)
                .Where(b => DbFunctions.TruncateTime(b.ReleaseDate)
                    == DbFunctions.TruncateTime(pubdate))
                .Select(AsProductDtO);
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }

    }
}
you can get the complete source code form here

Conclusion

In this article we have seen how to create a REST API using Attribute Routing

Reference

http://www.asp.net/web-api/overview/web-api-routing-and-actions/create-a-rest-api-with-attribute-routing

Page copy protected against web site content infringement by Copyscape

About the Author

Rama Sagar
Full Name: RamaSagar Pulidindi
Member Level: Silver
Member Status: Member,MVP
Member Since: 12/30/2012 1:51:40 AM
Country: India
ramasagar
http://www.ramasagar.com
A Software Profesional working in Microsoft .NET technologies since year 2008, and I work for Dake ACE. I am passionate about .NET technology and love to contribute to the .NET community at Dot Net Funda

Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)