Creating CRUD API in ASP.NET Core 2.0

Problem

How to create a CRUD Web API using ASP.NET Core.

Solution

In an empty project update Startup class to add services and middleware for MVC:

Add a service and domain model:

Add input and output models (to receive and send data via API):

Add a controller for the API with service injected via constructor:

Discussion

ASP.NET Core gives a unified mechanism for creating MVC and Web API application. The key difference is that Web API will return JSON (or XML) and HTTP status codes instead of views, in order to communicate with the client.

Routing

It is common to use attribute based routing (along with verb attributes) for Web API and conventional routing for MVC. The following URI’s will reach the controller:

We can also define nested URI’s e.g. below is a Reviews controller such that for every movie there could be zero or more reviews:

Note that identifier for parent resource (Movie) is part of the route and can be part of action methods. The following URI’s will reach the controller:

Models

Model in MVC is a misunderstood term because it implies that there is only one model, which isn’t correct. We have various different type of models in our application, for instance, input, output, view, domain, entity etc. These models are part of different layers and abstract away different concepts. See DDD and SOLID book for a detailed discussion.

The key point to remember when developing Web API is that the models being received and sent by the controller are Data Transfer Objects (DTO) and are distinct from domain or entity models.

Retrieve (GET)

A successful GET returns 200 (OK) status code along with the data.

If an item isn’t found, it returns 404 (Not Found).

Create (POST)

A successful POST returns 201 (Created) and sets the location header on HTTP response to point to the new item’s URI.

For issues with input model, a 400 (Bad Request) is returned. Also for nested resources, if parent isn’t found, a 404 (Not Found) can be returned.

Update (PUT)

A successful PUT returns 204 (No Content).

For issues with input model, a 400 (Bad Request) is returned. Also for nested resources, if parent isn’t found, a 404 (Not Found) can be returned.

Update (PATCH)

Although less frequently used, we can update parts of our data using PATCH verb. Content-Type for PATCH update should be application/json-patch+json.

Request body needs to contain an array of patch operations to apply to our model and action parameter needs to use JsonPatchDocument<T> to receive these operations:

Here we 1) retrieve a model from data source, 2) convert into input model, 3) apply patch, 4) validate and 5) update data source.

The table below lists patch operations and their usage description:

Delete (DELETE)

A successful DELETE returns 204 (No Content).

For nested resources, if parent isn’t found, a 404 (Not Found) can be returned.

Validation (POST/PUT/PATCH)

Input models can be validated using data annotations or custom code, as discussed here. A status code of 422 (Unprocessable Entity) can be returned to indicate validation failure to client. There is no built-in Action Result for this however it is easy to create one:

Now in POST/PUT/PATCH you could check for validation issues and return this result:

In the sample code I’ve also create a helper method in base controller:

Note: Postman file included with the sample contains HTTP requests for GET, POST, PUT, DELETE and PATCH.

Source Code

GitHub: https://github.com/TahirNaushad/Fiver.Api.Crud

Leave a Reply