NET 6 Web API — Baby Steps

Fardeen Khan
Code Panthers
9 min readMar 12, 2023

--

This is the first article from an extended series on NET 6.0 API development. Follow the below links for Later parts

  • Part 1: NET 6 Web API — Baby Steps (You are here)

The List will grow over time

What are we doing here

Well, we are here to learn a lot, starting with

  • A brief intro to APIs
  • The basics of .NET 6 Framework
  • Create an API project in .NET 6

So let's get Started

Application Programming Interface aka API

APIs act as an interface/bridge for communication between two software components that may differ from each other in terms of

  • Architecture
  • Underlying code and structure
  • Protocols they run on
  • Platforms they target

And much more.

An Example

API Visualization
API Visualization (Reference)

Think of any time you have used the Uber app. The application you interact with resides on your mobile phone but through the Internet connection on your device you receive all the information required to

  • Book a ride
  • Select from available rides
  • Pay the fare
  • Post a review or get help

There are many more such interactions that happen seamlessly with just a touch on your device. But behind the scenes, everything is mostly an API call.

You are as a user, making requests for resources from the Uber web server which delivers the responses which are then delivered to you via the internet. You make use of these responses to create more requests and so on.

Just like you, there are millions of people who use the Uber app on a daily basis, but all that complex logic is executed on some remote server and all the things you need are delivered to your doorstep via an API call.

It was an API all along

ASP.NET Core

In the words of its creator (Microsoft),

ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-enabled, Internet-connected apps.

With the power of interoperability, strong language support refined through decades in the form of C# and continued support by the giant that is Microsoft, ASP.NET Core technology has established itself as the go-to solution for many of the legacy and modern applications

Note- We are not discussing the entire suite of NET Family which includes support for writing Mobil/Web/Desktop applications. We are only focusing on ASP.NET Core 6.0 in terms of API Development

Things you can build with ASP.NET Core

  • Build web apps and services, Internet of Things (IoT) apps, and mobile backends.
  • Use your favorite development tools on Windows, macOS, and Linux.
  • Deploy to the cloud or on-premises.

Do all of the above and much more through the power of NET 6, which adds a whole other suite of benefits making the framework more unified and easier to approach

Benefits of NET 6

  • Simplified development: Getting started is easy. New language features in C# 10 reduce the amount of code you need to write. And investments in the web stack and minimal APIs make it easy to write smaller, faster microservices quickly.
  • Better performance: It is the fastest full-stack web framework, which lowers compute costs if you’re running in the cloud.
  • Ultimate productivity: .NET 6 and Visual Studio 2022 provide hot reload, new git tooling, intelligent code editing, robust diagnostics and testing tools, and better team collaboration.

Today we will be focusing on leveraging the NET 6 framework to build a starter API project.

Simple API Project in NET 6

Our end goal with this series of articles is to create a full-blown Inventory management system with Microservices architecture deployed to Cloud through CI/CD pipeline, and so much more.

That’s probably too much for the beginning. So we will focus on creating a very simple CRUD API around managing categories, each having a name and a description. For now we will be adding sone dummy data only, not relying on any Database. The user should be able to

  • Add a new category
  • See all the categories
  • Delete a category
  • Finally, update a category

Prerequisites

  1. Install Visual Studio 2022 Community edition from here
  2. Make sure to select the component ASP.NET and web development selected in the installer menu
  3. Install Postman. It’s a tool we would use for testing our APIs later on
  4. Install dotnet cor

You can use any alternative code editor like VSCode or even Notepad if you like, but make sure you have the dotnet-sdk installed as well.

That’s it, so let’s start with the project

Coding begins here

Create a new Project

  1. Open Visual Studio 2022 > Create a new project
  2. For project type select > ASP.NET Core Web API with C#
  3. Fill in the following project details
    - Solution Name: InventoryMgmt
    - Project Name: InventoryMgmt.WebAPI
  4. For the rest of the settings refer to this screengrab

We will add Swagger at a later point of time

Create the Project using dotnet cli

# Create the solution directory
mkdir InventoryMgmt
cd InventoryMgmt

# Create the solution
dotnet new sln --name InventoryMgmt

# Create the API project
dotnet new webapi --framework "net6.0" --name InvnetoryMgmt.WebApi --output InventoryMgmt.WebApi

# Add the project to the solution file
dotnet sln InventoryMgmt.sln add InventoryMgmt.WebApi

After the project is created, delete the generated files
- WeatherForecast.cs
- Controllers/WeatherForecastController.

Add Category Data Model

As we are going to CRUD operations around the Category Entity we need to define it’s properties and behaviors

Properties

  • Id — Unique identifier
  • Name — String
  • Description — String
  • IsActive — Boolean
  • CreatedAt — DateTime
  • CreatedBy — Int (User id)

Steps

  1. Create a new directory Domain (this path will store all our Data Objects)
  2. Add a new class using the shortcut — Ctrl + Shift + A, name Category
  3. Add the below code to the new class
public class Category
{
public Category(int id, string name, string description, bool isActive, DateTime createdAt, int createdBy)
{
Id = id;
Name = name;
Description = description;
IsActive = isActive;
CreatedAt = createdAt;
CreatedBy = createdBy;
}

public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedAt { get; set; }
public int CreatedBy { get; set; }
}

Add CategoryController

For each resource that we define and expose through our API is accessed through a controller. Usually, we have one controller mapped for operation one on Entity/Resource. We will follow the same approach here as well.

All the operations that we perform on an entity via a controller are known as Actions

Actions on Category

  • GetAll
  • GetByID
  • Add
  • Update
  • Delete
  • DeleteAll

Steps

  1. Create a new directory Controllers (this path will store all our Controller code)
  2. Add a new controller class CategoryController
  3. Add the below code to the new class
[Route("api/[controller]")]
[ApiController]
public class CategoryController : Controller
{
private List<Category> _categories;

public CategoryController()
{
var now = DateTime.Now; ;

_categories = new List<Category>
{
new Category(id: 1, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 2, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 3, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 4, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 5, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 6, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 7, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
};
}
[HttpGet()]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<List<Category>> GetAll()
{
return Ok(_categories);
}

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id)
{
Category? category = _categories.FirstOrDefault(c => c.Id == id);
if (category == null)
{
return NotFound($"Category with id {id} not found");
}
return Ok(category);
}

[HttpPost()]
[ProducesResponseType(StatusCodes.Status200OK)]
public IActionResult Add([FromBody] Category category)
{
category.Id = _categories.Count() + 1;
_categories.Add(category);
return Ok("Category Added Succesfully");
}

[HttpPut()]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Consumes(MediaTypeNames.Application.Json)]
public IActionResult Update([FromBody] Category category)
{
if (category == null)
{
return BadRequest("No Category data was passed");
}
else
{
Category? occurence = _categories.FirstOrDefault(c => c.Id == category.Id);
if (occurence == null)
{
return NotFound($"Category with id {category.Id} not found");
}
else
{

_categories.Remove(occurence);
_categories.Add(category);
return Ok("Update successfull");
}
}
}

[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult Delete(int id)
{
Category? category = _categories.FirstOrDefault(c => c.Id == id);
if (category == null)
{
return NotFound($"Category with id {id} not found");
}
else
{
bool resukt = _categories.Remove(category);
if (resukt)
{
return Ok($"Category id {id}, removed successfully");
}
else
{
return StatusCode(StatusCodes.Status500InternalServerError, "Something went wrong. Please try again");
}
}
}


[HttpDelete()]
[ProducesResponseType(StatusCodes.Status200OK)]
public IActionResult DeleteAll()
{
_categories.Clear();
return Ok("All categories have been removed");
}
}

Code Breakdown

In the Category Controller have a defined an in memory object list to hold static Category data (as we are not using any Database backend as of now)

_categories = new List<Category>
{
new Category(id: 1, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 2, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 3, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 4, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 5, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 6, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
new Category(id: 7, name: "Book", createdAt: now, description: "Ready to sell books from all genres"),
};

For now, his collection will be our data source

Notice that we have an [Route] attribute at the top of the controller definition. This helps specify the URL path to follow in order to invoke the controller.

Suppose your application is running on the HTTP/S URL https://localhost:5001. With the route attribute set to api/[controller], the URL we will use to access the Category controller will become https://localhost:5001/api/category

This attribute is optional and if not added, the URL would change to https://localhost:5001/category

Next, we have the various methods that correspond to the different actions we are performing on the Category Resource. For each of the methods we have some attributes shared between them

  • [HttpGet()] / [HttpDelete()], etc are the HTTP verbs or actions that we perform as part of the action
  • [HttpGet(“{id}”)] here is a bit different as it provides a parameter at the end of the route. We can add as my parameters separated by “/”For this action the URL would be something like

https://localhost:5001/api/category/3

  • [ProducesResponseType(StatusCodes.Status200OK)] specifies what all status codes can be sent from this action as part of the response.
  • [Consumes(MediaTypeNames.Application.Json)] adds a filter on the Content Type accepted as part of the Request
  • Model Binding allows the action to parse the incoming data directly into a Data class. So no need to handle serialization and all
    public IActionResult Update([FromBody] Category category)

Sending the Response

Consider the Delete action below

public IActionResult Delete(int id)
{
Category? category = _categories.FirstOrDefault(c => c.Id == id);
if (category == null)
{
return NotFound($"Category with id {id} not found");
}
else
{
bool resukt = _categories.Remove(category);
if (resukt)
{
return Ok($"Category id {id}, removed successfully");
}
else
{
return StatusCode(StatusCodes.Status500InternalServerError, "Something went wrong. Please try again");
}
}
}

The response type is of class IActionResult . The various response types returned in the above action

  • NotFound — 404 status
  • Ok — 200 status
  • StatusCode method — Can be used for any status code as

Running your application

  • The first time you run the WebAPI you would receive the below warning. This is because we have selected to use HTTPS as the protocol for our APIs and that has a requirement for a Certificate to be installed on your system for using security features. Just agree and continue
  • In the debug panel you will see the URL on which the server is running, such as
    Microsoft.Hosting.Lifetime: Information: Now listening on: https://localhost:5001
  • Now you can open a browser/postman and try out the various actions.

Example curl request for adding the Category data

curl --location 'https://localhost:5001/api/category' \
--header 'Content-Type: application/json' \
--data '{
"id": 7,
"name": "Book1",
"description": "Ready to sell books from all genres",
"isActive": true,
"createdAt": "2023-03-12T22:58:14.1516161+05:30",
"createdBy": 1
}'

Note that when adding new category item, it is not reflected back in the GetAll action. We will solve this problem by moving the data source to a PostgreSQL database in the next article. See you there

You can find the source code for this application here

Thank you for dropping by!!

Support me by sponsoring a coffee here https://www.buymeacoffee.com/fardeen9983

--

--