C# – Correct usage of HTTP VERBS in custom REST implementation

asp.net-corecrest

I have a server-side service (using ASP.NET Core) that should provide a REST API to various clients.

Behind the service, I use a SQL server for data storage.

The controller has the following route attribute:

[Route("api/[controller]")]
[ApiController]
public class CustomDataController : ControllerBase
{…}

There are data provider methods:

[HttpGet(nameof(GetDataForGuest))]
public async Task<IQueryable<Specs>> GetDataForGuest(int skip, int take, Guid organizationID) => await dataProvider.GetDataAsync<Specs>(skip, take, organizationID);

There are methods to create or update data on the server:

[HttpPost(nameof(SaveDataToServer))]
public async Task SaveDataToServer([FromBody] List<Specs> specs) => await dataProvider.SaveDataAsync<Specs>(specs, isNewData: true);

According to many articles (like this one), GET is for returning some resource, POST is for creating and PUT is for updating:

  • GET — For returning resources
  • POST — For creating a new resource
  • PUT — For updating a resource
  • PATCH — For updating a resource
  • DELETE — For deleting a resource

However, as you can see, my methods are only facades, the data is saved by the data provider, and I can decide based on a bool variable to insert or update an incoming record.

As you can also guess, I don't use traditional REST URLs (like api/user/1), as I need complex data, so my URLs look like this:

https://192.168.0.101:8080/api/customdata/GetDataForGuest?skip=0&take=10&organizationID=58b77372-abbc-435e-9a5b-d77bc05129c7

Currenty I get data with the HttpPost for both inserting new records and updating existing ones (and it works normally). My concerns are about best practice: should I use HttpPut when I want to update an existing record?
According to the specifications, using PUT is idempontent by definition while POST is not, so executing the query should not depend on how many times it was called.

On the client side, I use some query building (based on parameters) and I call the method with a POST action:

public async Task SaveDataToServer(string methodName, List<T> data, bool isNewData)
{
  var parameters = GetParameters(methodName, isNewData);
  var baseUri = new Uri(baseUriString, methodName);
  var targetUri = UriBuilding(baseUri, parameters).AbsoluteUri;
  var result = await httpClient.PostAsync<List<T>>(targetUri, data);
}

So using only POST is considered as best practice? Or should I separate the update actions to another method marked with HttpPut? Does it matter considering that the logic behind the methods decides what will happen and not the verb?

Best Answer

According to this great tutorial, there are several problems with my initial approach.

  • Good: /users/12345
  • Poor: /api?type=user&id=23
  • POST Create
  • GET Read
  • PUT Update/Replace
  • PATCH Update/Modify
  • DELETE Delete

So it looks I have to redesign my customized RESTless API but following these suggestions, it will be much more REST-like.

Related Topic