Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"True" REST routing via MVC 4 Web API

TL;DR Summary: Can I configure MVC Web API routing for HTTP GET, PUT & DELETE?

I've been looking into replacing our old Data Access Layer (a DLL based on DataSets and TableAdapters) with a private API, with a view to creating a public API if it's successful. I've done some work with MVC 4 to refresh our frontend, and loved working with it, so it seems sensible to explore the "Web API" project type before diving into WS- or WCF-based libraries.

An initial demo allows me to return XML/JSON nicely, for example:

//service.url/api/Users

... returns a list of users, while a specific user's details can be accessed via:

//service.url/api/Users/99

So far, so RESTful. However, in order to truly map URIs to resources I want to do an HTTP PUT (new user) or HTTP DELETE (remove user) to the the URI listed above. In all of the examples I've seen for these projects, along with the Scaffolds provided in Visual Studio, this convention is followed:

//service.url/api/Users/Create

//service.url/api/Users/Delete/99

//service.url/api/Users/Update/99

... and so on. This feels like side-stepping the issue to me, which is a shame when what's there has been put together so nicely!

Any thoughts on how best to approach this?

like image 754
Richard A. Avatar asked Dec 15 '22 15:12

Richard A.


2 Answers

What you want is the default in MVC Web API. I'm not sure what you are looking at but here is a great example of routing the Get/Post/Put/Delete to actions.

For example you may want:

public class UsersController : ApiController
{
  // GET http://service.url/api/Users/1
  [HttpGet]
  public User GetUser(int id);

  // POST http://service.url/api/Users/?name=richard...
  [HttpPost]
  public User AddUser(User model);      

  // PUT http://service.url/api/Users/?id=1&name=Richard...
  [HttpPut]
  public User UpdateUser(User model);

  // DELETE http://service.url/api/Users/1
  [HttpDelete]
  public User DeleteUser(int id);
}

I've explicitly set these, but the GetUser and DeleteUser don't need the prefix because they start with the matching HTTP method.

like image 66
Erik Philips Avatar answered Jan 03 '23 19:01

Erik Philips


The link provided by Erik is a good start, but I see how it can confuse the situation when looking for a simple RESTful API that makes use of the HTTP verbs to perform these CRUD actions. If you're looking to use the HTTP verbs of GET, PUT, POST, and DELETE (and possibly PATCH, but I'm not covering that here) and you're ok with using convention, then the following would work:

public class UsersController : ApiController
{
    // GET http://service.url/api/Users
    public User GetAllUsers(){ ... }

    // GET http://service.url/api/Users/1
    public User GetUser(int id){ ... }

    // POST http://service.url/api/Users/
    // User model is passed in body of HTTP Request
    public User PostUser([FromBody]User model){ ... }

    // PUT http://service.url/api/Users/1
    // User model is passed in body of HTTP Request
    public User PutUser(int id, [FromBody]User model){ ... }

    // DELETE http://service.url/api/Users/1
    public User DeleteUser(int id){ ... }
}

Note that the attributes on the method are not needed when using the HTTP verb action convention in Web API. Also, note that I use the [FromBody] attribute on the User parameter for POST and PUT to denote that the body contains the data I wish to send. This may not be most convenient for POST if you're trying to append to a resource, and I have not tried creating/modifying data through query parameters using Web API. It certainly makes the call feel very clean to place your data in the body. "POST/PUT this content in the body at this resource."

Also, the way I read PUT in the spec, and I could very well be wrong, is that it acts as a replace. That also makes sense given the last line above. I'm PUTting this resource in this location, replacing what was already there. The spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) states: "If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server." The term they use is "modified" so I guess that leaves enough room for interpretation for the end user. That's where PATCH comes in (https://www.rfc-editor.org/rfc/rfc5789), but I don't have enough information to comment on that at this time.

like image 36
Rich Visotcky Avatar answered Jan 03 '23 19:01

Rich Visotcky