.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

** Note ** Jesse is currently looking for a new position. You can learn more about him at https://jesseliberty.bio Thank you. 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. His latest book, Building APIs with .NET, is now available wherever you buy your books. Liberty 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 13 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. Hey there, You’ve done a great job. I will definitely digg it and individually recommend to my friends. I am confident they will be benefited from this website.

  2. Hello there, You have done a fantastic job. I will definitely digg it and for my part recommend to my friends. I am sure they’ll be benefited from this site.

  3. sa影视's avatar sa影视 says:

    寒鸦守夜人高清版手机在线观看,信念崩塌后重新站起童话冒险明亮治愈镜头语言克制有力细节经得起看希望感在低谷里慢慢亮起寒鸦守夜人高清版手机在线观看

  4. KeithDit's avatar KeithDit says:

    Macksood Urology Urological Services: Generic Cialis without a doctor prescription – Macksood Urology Urological Services

  5. Russelltix's avatar Russelltix says:

    viagra https://macksoodurology.com/ed-medications/ erectile dysfunction pills online

  6. Hey there, You’ve done a fantastic job. I will certainly digg it and for my part suggest to my friends. I am confident they will be benefited from this website.

  7. Craigpes's avatar Craigpes says:

    https://mexicorx.online/# order antibiotics from mexico

  8. Right now it seems like Expression Engine is the top blogging platform available right now. (from what I’ve read) Is that what you’re using on your blog?

  9. Terrypum's avatar Terrypum says:

    https://mexicorx.online/# order medication from mexico

  10. Jeraldbasse's avatar Jeraldbasse says:

    https://sans-ordonnance.club/# Quand une femme prend du Viagra homme

  11. Craigpes's avatar Craigpes says:

    https://sansordonnance.shop/# Viagra femme sans ordonnance 24h

  12. Jeraldbasse's avatar Jeraldbasse says:

    https://sepharm.shop/# Svenska Pharma

  13. Williamisono's avatar Williamisono says:

    meds from mexico: reliable rx pharmacy – pharmacy in mexico online

  14. Right now it sounds like Drupal is the preferred blogging platform available right now. (from what I’ve read) Is that what you’re using on your blog?

  15. Jeraldbasse's avatar Jeraldbasse says:

    https://mexicorx.online/# mexican pharmacy prices

  16. Jeraldbasse's avatar Jeraldbasse says:

    https://svpharm.xyz/# kolla blodtryck apotek

  17. Williamarini's avatar Williamarini says:

    Levitra tablet price PrecisionCare Pharm Buy Levitra 20mg online

  18. 币圈版的“民间武术团”——名字叫学院,其实是一帮爱好者自己练。Cryptify Hub就是这种画风:没有正规课程,没有考核标准,主打一个“大家一起玩”。社群里有人分享工具链接,有人讨论行情,有人吹水。作为社群型品牌,它的生命力在于活跃度,而不是权威性。所以用它找链接、参与讨论都可以,但别把它的话当圣旨。民间组织嘛,听听就好。

  19. Cryptify Hub's avatar Cryptify Hub says:

    一个有趣的观察:币圈里最坑人的往往是那些热情洋溢的“导师”。而Cryptify Hub这种一句话不多说的网址大全,反而安全——因为它不怂恿你做任何事。它只是把工具链接放那里,你自己看着办。在这个充满噪音的圈子里,安静本身就是一种美德。

  20. Williamarini's avatar Williamarini says:

    BlueLine BlueLine BlueLine

  21. excellent points altogether, you simply received a new reader. What could you recommend about your post that you made a few days ago? Any certain?

  22. constantly i used to read smaller articles that also clear their motive, and that is also happening with this post which I am reading here.

  23. playcity's avatar playcity says:

    I like the valuable information you provide in your articles. I will bookmark your weblog and check again here regularly. I’m quite certain I will learn many new stuff right here! Best of luck for the next!

  24. Aaronedula's avatar Aaronedula says:

    Вывод запоя в клинике Сочи: лечение алкогольной интоксикации, капельница, детоксикация, помощь нарколога на дому и в стационаре круглосуточно, анонимно
    Получить больше информации – вывод из запоя цена в сочи

  25. pokerstars's avatar pokerstars says:

    I am curious to find out what blog platform you are using? I’m having some minor security issues with my latest blog and I would like to find something more risk-free. Do you have any recommendations?

  26. OctavioAmoub's avatar OctavioAmoub says:

    pharmacy wholesalers canada: reputable canadian online pharmacies – Easy North RX

  27. Aaronedula's avatar Aaronedula says:

    звоните круглосуточно по телефону горячей линии клиники: наши специалисты готовы оказать необходимую помощь в решении проблемы алкогольной зависимости.
    Подробнее тут – http://vivod-iz-zapoya-sochi22.ru/

  28. Hello are using WordPress for your blog platform? I’m new to the blog world but I’m trying to get started and set up my own. Do you need any html coding knowledge to make your own blog? Any help would be greatly appreciated!

  29. OctavioAmoub's avatar OctavioAmoub says:

    Easy North RX: canada pharmacy online – canadian pharmacy world reviews

  30. Jamesacutt's avatar Jamesacutt says:

    https://mexicaredirect.com/# reliable rx pharmacy

  31. Randynek's avatar Randynek says:

    http://fleximedsindia.com/# mail order pharmacy india

  32. whoah this blog is great i like reading your posts. Stay up the great work! You already know, a lot of persons are looking around for this information, you could help them greatly.

  33. Excellent post! We are linking to this great content on our site. Keep up the good writing.

  34. JamesSog's avatar JamesSog says:

    real canadian pharmacy: Easy North RX – Easy North RX

  35. Jerrywex's avatar Jerrywex says:

    canadian pharmacy online store canadian pharmacy store official website pharmacy rx world canada

  36. Jamesacutt's avatar Jamesacutt says:

    https://fleximedsindia.shop/# Online medicine order

Leave a Reply

Your email address will not be published. Required fields are marked *