Attribute Routing in Web API 2
With the release of Web API 2 there are few improved & new features been introduced. Those are
- External Authentication
- Enabling cross origin request
- Use OWIN to host Web API in an Azure worker Role
- IHttpActionResult, a New Way to Create Responses in Web API
- Attribute Routing
- Using $select, $expand, and $value in Web API OData
In this blog I am going to talk about Attribute routing in detail.
Before Web API 2 comes for routing in web API what we have used in conventional routing. In this normally what we have in a single API controller
ex:- Employee Controller
- Get(int Id) // Get Employee By Id
- Get() // Get All Employees
- Post()
- Put()
- Delete()
You can get more details on conventional routing here
The constraint here is if we want to get Leave Records by Employee Id we will have to create a different controller. We cannot have that in the same controller. Attribute Routing solves this issue. Attribute routing supports some of the URI patterns which are commonly used in REST API’s which are not supported by Conventional Routing.
API Versioning
If you have different versions of your API you can specify that in the URI template so the request will be routed to the correct version of the code.
ex :-
/api/v1/employees
/api/v2/employees
Overloaded URI segments
ex :-
/api/employees/1
/api/employees/onsite
Here first one will return employee by ID 1 and second one will return collection of employees who are in onsite.
Multiple parameter types
ex :-
/api/employees/1
/api/employees/2013/06/16
Here 1 is int and other one takes a date time as parameter.
Enabling Attribute Routing
Add the following code inside class WebApiConfig. You can find it here.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
}
}
Adding Route Attribute
Following is an example of adding routing attribute
public class EmployeeController : ApiController
{
[Route("customers/{employeeId}/leaves")]
public IEnumerable<Leave> GetLeaveByEmploeeId(int employeeId)
{ ... }
}
Route Prefixes
Most of the methods in the controller has a common part in all the URL Templates.
ex:-
public class EmployeesController : ApiController
{
[Route("api/employees")]
public IEnumerable<Employee> GetEmployees() { ... }
[Route("api/employees/{id:int}")]
public Employee GetEmployee(int id) { ... }
[Route("api/employees")]
public HttpResponseMessage CreateEmployee(Employee employee) { ... }
}
For this kind of a controller you can use Route Prefix As below.
[RoutePrefix("api/employees")]
public class EmployeesController : ApiController
{
[Route("")]
public IEnumerable<Employee> GetEmployees() { ... }
[Route("{id:int}")]
public Employee GetEmployee(int id) { ... }
[Route("")]
public HttpResponseMessage CreateEmployee(Employee employee) { ... }
}
Route Prefix Can include Parameters as well.
Ex:-
[RoutePrefix("customers/{employeeId}")]
public class EmployeeController : ApiController
{
[Route("orders")]
public IEnumerable<Leave> Get(int employeeId) { ... }
}
If in case if you want to use a different URL template for a selected method inside a controller which has a route prefix you can override it as below.
[RoutePrefix("api/employees")]
public class BooksController : ApiController
{
[Route("~/api/employees/{emploeeId:int}/leaves")]
public IEnumerable<Leave> GetLeavesByEmployeeId(int authorId) { ... }
}
Route Constraints
Route constraints let you restrict how the parameters in the route template are matched. The general syntax is "{parameter:constraint}".
Ex:
[Route("users/{id:int}"]
public User GetUserById(int id) { ... }
[Route("users/{name}"]
public User GetUserByName(string name) { ... }
Here, the first route will only be selected if the "id" segment of the URI is an integer. Otherwise, the second route will be chosen.
Following are the constraints supported.
alpha | Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) | {x:alpha} |
bool | Matches a Boolean value. | {x:bool} |
datetime | Matches a DateTime value. | {x:datetime} |
decimal | Matches a decimal value. | {x:decimal} |
double | Matches a 64-bit floating-point value. | {x:double} |
float | Matches a 32-bit floating-point value. | {x:float} |
guid | Matches a GUID value. | {x:guid} |
int | Matches a 32-bit integer value. | {x:int} |
length | Matches a string with the specified length or within a specified range of lengths. | {x:length(6)} |
long | Matches a 64-bit integer value. | {x:long} |
max | Matches an integer with a maximum value. | {x:max(10)} |
maxlength | Matches a string with a maximum length. | {x:maxlength(10)} |
min | Matches an integer with a minimum value. | {x:min(10)} |
minlength | Matches a string with a minimum length. | {x:minlength(10)} |
range | Matches an integer within a range of values. | {x:range(10,50)} |
regex | Matches a regular expression. | {x:(^\d{3}-\d{3}-\d{4}$)} |
Optional URI Parameters and Default Values
If you want to make a URL parameter optional then that is also supported in Web API 2. In such a method you can set the default value of the parameter inside the URL template itself.
public class BooksController : ApiController
{
[Route("api/books/locale/{lcid=1033}")]
public IEnumerable<Book>
GetBooksByLocale(int lcid) { ... }
}
Above features have given us the same REST API URL template experience in web API as well.
Happy Coding !!!!
Thanks for sharing this great information..
ReplyDeleteBest Web Design Company In Bangalore | best website designers in bangalore | best website design company in bangalore | best web designers in bangalore