.NET APIs Part 5 – All the CRUD APIs

In the previous posting we saw how to create an API to get all the cars in our database. In this posting we’ll look at the remaining CRUD (Create Review Update Delete) operations.

As you may remember, we created a controller named CarController. ASP.NET will strip off the word Controller, leaving us with Car, which we will use to access the endpoints of our API.

An endpoint is just a URL that takes us to the operation we want.

We looked at GetAll, let’s take a look at Get. In this case, we have an id for the car we want, but we want all the details of that car. Simple!

First we need a method in our controller:

[HttpGet("{id}")]
public async Task<ActionResult<Car>> Get(int id)
{
   var car = await _carRepository.Get(id);
   if (car == null)
   {
      return NotFound();
   }
   return car;
}


Notice that next to the HttpGet attribute we indicate that the endpoint will take the id of the car we want

[HttpGet("{id}")]

This means we need to modify the URL to access the endpoint by adding the actual id of the desired record.

The first thing we do is call the repository, passing in the id.

public async Task<Car?> Get(int id)
{
   var query = "select * from car where id=@id";
   using var db = databaseConnectionFactory.GetConnection();
   return await db.QuerySingleOrDefaultAsync<Car>(query, new {id});
}

In the Get method of the repo we create our query, get our connection and execute the query returning the value we retrieved (if any). This is very close to what we did previously.

Back in the controller, we check to ensure that we received a Car. If not, we return NotFound which is a shorthand way of returning a 404 message. Otherwise we return the Car as a Json object. You can see this in Postman:

We’ll issue a Get command passing in the URL, ending with the id of the car we want (in this case 4)

 

 

 

Notice that we get back a 200, indicating success. In the body of the returned Json we get back all the details of the Car. (If you decide to use DTOs you can get whatever subset of the information makes sense):

{
    “id”: 4,
    “name”: “subaru impreza”,
    “mpg”: “16”,
    “cylinders”: “8”,
    “displacement”: “304”,
    “horsepower”: “150”,
    “weight”: “3433”,
    “acceleration”: “12”,
    “model_year”: “22”,
    “origin”: “usa”,
    “is_deleted”: “0”
}

Post

Adding a Car to the database is quite similar. We need a method in the controller and one in the repo. Here is the controller method:

[HttpPost]
public async Task<ActionResult<Car>> Post([FromBody] Car car)
{
   try
   {
      car = await _carService.Insert(car);
   }
   catch (Exception e)
   {
      return BadRequest(e); 
   }

   return CreatedAtAction(nameof(Get), new { id = car.Id }, car);
}

Look at the attribute in the parameter ([FromBody]. This indicates to the API that the data needed to insert this Car will be in the body of the call. The alternative is FromQuery. You can, in fact, use both in one call.

Note: CreatedAction causes a return code of 201, which is what we want. Here’s the body we’ll insert:

{
        “name”: “chevrolet chevelle malibu”,
        “mpg”: “18”,
        “cylinders”: “8”,
        “displacement”: “307”,
        “horsepower”: “130”,
        “weight”: “3504”,
        “acceleration”: “12”,
        “model_year”: “70”,
        “origin”: “usa”,
        “is_deleted”: “0”
    }

When we click Send this data is sent to the API which returns 201 (created) and in the body of the returned data we see the new id assigned to this car

{
    “id”: 409,
    “name”: “chevrolet chevelle malibu”,
    “mpg”: “18”,
    “cylinders”: “8”,
    “displacement”: “307”,
    “horsepower”: “130”,
    “weight”: “3504”,
    “acceleration”: “12”,
    “model_year”: “70”,
    “origin”: “usa”,
    “is_deleted”: “0”
}

Service Class

Notice that this time, instead of calling the Repo directly, the method in the controller calls into a service class. A service class is a great way to get the logic out of the controller, where it does not belong, without putting it into the repo, where it also does not belong.

Here’s the top of the CarService

public class CarService : ICarService
{
   private readonly ICarRepository _carRepository;

   public CarService(ICarRepository carRepository)
   {
      _carRepository = carRepository;
   }

   public async Task<Car> Insert(Car car)
   {
      var newId = await _carRepository.UpsertAsync(car);
      if (newId > 0)
      {
         car.Id = newId;
      }
      else
      {
         throw new Exception("Failed to insert car");
      }
   return car;
   }

All the logic associated with this insert (e.g., making sure we get back a legitimate id from the repository, etc.) is encapsulated in the service.

This leaves the repository free to just talk to the database,

public async Task<int> UpsertAsync(Car car)
{
using var db = databaseConnectionFactory.GetConnection();
var sql = @"
DECLARE @InsertedRows AS TABLE (Id int);
MERGE INTO Car AS target
USING (SELECT @Id AS Id, @Name AS Name, @Model_Year AS Model_Year, 
@Is_Deleted AS Is_Deleted, @Origin AS origin ) AS source 
ON target.Id = source.Id
WHEN MATCHED THEN 
UPDATE SET 
Name = source.Name, 
Model_Year = source.Model_Year, 
Is_Deleted = source.Is_Deleted,
Origin = source.Origin
WHEN NOT MATCHED THEN
INSERT (Name, Model_Year, Is_Deleted, Origin)
VALUES (source.Name, source.Model_Year, 
source.Is_Deleted, source.Origin)
OUTPUT inserted.Id INTO @InsertedRows
;

SELECT Id FROM @InsertedRows;
";

var newId = await db.QuerySingleOrDefaultAsync<int>(sql, car);
return newId == 0 ? car.Id : newId;
}

Rather than having an insert and an update method, we combine that logic into this upsert method. This is a common idiom for database manipulation.

Note: to make this work, be sure to fill in all the fields for a car (or at least as many as you want to have in the Database.

Delete

As noted earlier, we will implement a soft delete; that is, rather than actually removing the data from the database, we’ll just set the is_deleted column to true. This allows us to reverse the action, and make the row not-deleted by simply changing that value to false.

[HttpDelete(“{id}”)]
public async Task<IActionResult> Delete(int id)
{
try
{
await _carService.Delete(id);
}
catch (Exception e)
{
return BadRequest(e);
}
return NoContent();
}

As you would expect, the endpoint takes an id (the id of the car we want to delete). The controller then hands that off to the service, which calls the repository which, in turn, marks that id as deleted:

public async Task<int> DeleteAsync(int id)
{
   using var db = databaseConnectionFactory.GetConnection();
   var query = "UPDATE car SET Is_Deleted = 1 WHERE Id = @Id";
   return await db.ExecuteAsync(query, new { Id = id });
}

If you are comfortable with SQL none of this will be very surprising. The key walkaway is:

Summary

In this post we saw that endpoints are just URLs with (potentially) data in the body of the request. The controller handles the URL and in our case passes the id or other data to the service. The service handles the (business) logic and then delegates talking to the database to the repository.

Book

This posting is excerpted from my forthcoming book Building APIs with .NET and C# to be released next year by Packt.

Unknown's avatar

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. Liberty is a Senior AI Engineer at the University of Pittsburgh Medical Center, and was a Team Lead and Senior Software Engineer for various corporations, a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a 21 year Microsoft MVP.
This entry was posted in Essentials. Bookmark the permalink.

2,765 Responses to .NET APIs Part 5 – All the CRUD APIs

  1. Gregoryven's avatar Gregoryven says:

    http://truehealthpharm.com/# cheap ed pills online

  2. RichardGit's avatar RichardGit says:

    pharmacy store: Buy generic 100mg Viagra online – 24 hour pharmacy near me

  3. RichardGit's avatar RichardGit says:

    cheap ed: True Health Pharm – buy erectile dysfunction treatment

  4. PatrickZoolf's avatar PatrickZoolf says:

    pet pharmacy: pet antibiotics and care – HappyPaws Pharmacy

  5. PatrickZoolf's avatar PatrickZoolf says:

    canadian pharmacy cialis 40 mg: Viagra tablet online – no prescription needed pharmacy

  6. PatrickZoolf's avatar PatrickZoolf says:

    pet antibiotics and care: dog and cat medicine supply – pet antibiotics and care

  7. PatrickZoolf's avatar PatrickZoolf says:

    True Health Pharm: True Health Pharm – True Health Pharm

  8. Gregoryven's avatar Gregoryven says:

    https://vitalcorepharmacy.shop/# legit pharmacy websites

  9. Gregoryven's avatar Gregoryven says:

    https://vitalcorepharmacy.shop/# cialis canadian pharmacy

  10. RichardGit's avatar RichardGit says:

    dog and cat medicine supply: pet med – pet pharmacy USA

  11. RichardGit's avatar RichardGit says:

    dog and cat medicine supply: dog and cat medicine supply – HappyPaws Pharmacy

  12. RichardGit's avatar RichardGit says:

    online pharmacy worldwide shipping: over the counter sildenafil – canadian pharmacy ed medications

  13. RichardGit's avatar RichardGit says:

    pet med: pet antibiotics and care – HappyPaws Pharmacy

  14. RichardGit's avatar RichardGit says:

    pet antibiotics and care: pet antibiotics and care – pet antibiotics and care

  15. RichardGit's avatar RichardGit says:

    sure save pharmacy: order viagra – canada pharmacy not requiring prescription

  16. RichardGit's avatar RichardGit says:

    how to get ed meds online: True Health Pharm – ed pills cheap

  17. RichardGit's avatar RichardGit says:

    buy erectile dysfunction pills online: True Health Pharm – ed medicine online

  18. RichardGit's avatar RichardGit says:

    legitimate online pharmacy usa: VitalCore Pharmacy – online canadian pharmacy reviews

  19. Archiebem's avatar Archiebem says:

    Этот увлекательный информационный материал подарит вам массу новых знаний и ярких эмоций. Мы собрали для вас интересные факты и сведения, которые обогатят ваш опыт. Откройте для себя увлекательный мир информации и насладитесь процессом изучения!
    Узнать больше – https://vivod-iz-zapoya-2.ru/

  20. BennieWalse's avatar BennieWalse says:

    mostbet güncel: mostbet

  21. Robertbix's avatar Robertbix says:

    mostbet resmi giriş: mostbet

  22. Robertbix's avatar Robertbix says:

    mostbet resmi giriş mostbet

  23. GregoryRox's avatar GregoryRox says:

    mostbet mostbet

  24. BennieWalse's avatar BennieWalse says:

    https://mostbetpl.top/# mostbet casino

  25. MartinEngam's avatar MartinEngam says:

    mostbet mostbet

  26. GregoryRox's avatar GregoryRox says:

    mostbet güncel adres: mostbet

  27. GregoryRox's avatar GregoryRox says:

    https://mostbettr.icu/# mostbet güncel adres

  28. GregoryRox's avatar GregoryRox says:

    mostbet güncel adres mostbet

  29. MartinEngam's avatar MartinEngam says:

    mostbet resmi: mostbet

  30. BennieWalse's avatar BennieWalse says:

    https://mostbetpl.buzz/# mostbet güncel giriş

  31. MartinEngam's avatar MartinEngam says:

    mostbet resmi giriş mostbet

  32. GregoryRox's avatar GregoryRox says:

    https://mostbettr.icu/# mostbet güncel

  33. MartinEngam's avatar MartinEngam says:

    mostbet casino mostbet

  34. MartinEngam's avatar MartinEngam says:

    mostbet mostbet

  35. MartinEngam's avatar MartinEngam says:

    mostbet mostbet

  36. GregoryRox's avatar GregoryRox says:

    mostbet güncel mostbet

  37. BennieWalse's avatar BennieWalse says:

    mostbet resmi giriş: mostbet

  38. MartinEngam's avatar MartinEngam says:

    mostbet kasyno: mostbet

  39. MartinEngam's avatar MartinEngam says:

    mostbet güncel giriş mostbet

  40. bet7k's avatar bet7k says:

    What i do not understood is in truth how you’re now not actually a lot more neatly-preferred than you might be right now. You’re very intelligent. You already know therefore considerably on the subject of this topic, produced me in my view imagine it from numerous numerous angles. Its like men and women are not involved until it is one thing to do with Woman gaga! Your personal stuffs excellent. Always care for it up!

  41. EarnestCor's avatar EarnestCor says:

    Great website you have here but I was wanting to know if you knew of any discussion boards that cover the same topics talked about here? I’d really love to be a part of group where I can get feed-back from other knowledgeable individuals that share the same interest. If you have any recommendations, please let me know. Thank you!
    Barcelona vip escorts

  42. lodi777's avatar lodi777 says:

    I know this web site offers quality depending content and extra information, is there any other website which provides such data in quality?

  43. fc178's avatar fc178 says:

    Usually I do not read post on blogs, however I wish to say that this write-up very forced me to try and do so! Your writing style has been amazed me. Thanks, quite great article.

  44. Для многих игроков удобство вывода средств — ключевой фактор при выборе казино. Не все хотят разбираться с электронными кошельками или криптовалютой, гораздо проще получить выигрыш сразу на банковскую карту. Поэтому популярность рейтингов с подобными площадками только растёт. В одном из таких списков можно увидеть рекомендацию играть в казино на деньги, ведь там собраны казино, которые без проблем выводят средства на карту.

  45. Jeremymug's avatar Jeremymug says:

    https://cassiteleri.top/# casino deneme siteleri

Comments are closed.