Restful API In .NET Core Using EF Core And Postgres

REST API is an application programming interface which can be used by multiple clients(or APPS) to communicate with a server.

Rest API is a kind of web-service which stores and retrieves necessary data for your application in a convenient format (e.g. JSON or XML).

It provides great flexibility to developers since it does not need any dependent code libraries to access the web-services as it is stateless.

Amongst the many protocols supported by REST, the most common one is HTTP.

When a request is sent from the client using a HTTPRequest, a corresponding response is sent from the server using HTTPResponse. The most widely used machine readable format supported for requests and responses are JSON (Javascript Object Notification) and XML (Extensible Markup Language).

REST was created by computer scientist ROY FIELDING.

REST APIs can be used to perform different actions. Based on the actions, the relevant method should be used. The following are the 5 methods supported by REST.

  1. GET - This method is used to retrieve a data from database / server.
  2. POST - This method is used to create a new record.
  3. PUT - This method is used to modify / replace the record. It replaces the entire record.
  4. PATCH - This method is used to modify / update the record. It replaces parts of the record.
  5. DELETE - This method is used to delete the record.

Restful Api In dotnet Core Using Ef Core And Postgres

Let us see this with an example. We know that mothers never get enough rest. But lets take these rest-less mommies as an example and see how they use Rest API. :)

Amongst the excessive demands by a newborn baby, diapering takes the first place on the leader board.

A mother wants everything best for the baby. So, it's obvious that the mother would want to choose the best diaper for her baby. So, she goes to a shopping website(assume: flipkart) and searches for diapers. This will send a HTTP Request to flipkart’s server to GET the list of all diapers. Flipkart’s server responds with a HTTP Response which will be a JSON object(assume) containing a list of diapers with some basic details. Flipkart’s website reads this Response and converts to human readable format and displays it on the webpage for the mother to see it.

After she chooses a particular diaper for her newborn baby and adds it to her list. This creates a POST request where a new record is created in flipkart’s database containing the diaper brand, size, quantity, price etc.

Her baby keeps growing and soon outgrows the newborn size. Suppose, the mother still likes the diaper brand and just wants to size up, all she has to do is just choose the new diaper size. When she updates the diaper size from size newborn to size 1, this triggers a PATCH method where everything else remains the same and only the size of the diaper is changed.

It is very common for the mother to change the current brand and decide to switch to an alternate the brand. Here, the mother will initiate a PUT request where the entire data containing previously chosen brand is modified and replaced with data corresponding to the newly chosen brand.

Finally, after a series of experiments involving several GETs, POSTs, PUTs and PATCHs, it's time for the mother to potty train the child. If she succeeds in training the child, then the diapers will no longer be required. This triggers a DELETE request.

PREREQUISITES

  1. Visual studio 2022 
  2. .Net Core 6 : ASP.NET Core is a new version of ASP.NET, developed by Microsoft. It is an open-source framework for developing web applications and API's and it can be run on Windows, Mac, or Linux. Asp.Net Core is a cross platform, high-performance, open-source framework for building modern, cloud-based, internet-connected applications.
  3. Entity Framework core: Entity Framework (EF) Core is a lightweight, extensible, open source and cross-platform version of the popular Entity Framework data access technology.
  4. Postgres Database : PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.

API CREATIONS STEPS

Step 1

Open Visual studio 2022 and create asp.net core webapi project.

Step 2

Install Npgsql.EntityFrameworkCore.PostgreSQL & Microsoft.EntityFrameworkCore.Tools from Nuget

Step 3

Create Product.cs and Order.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("product")]
public class Product {
    [Key, Required]
    public int id {
        get;
        set;
    }
    [Required]
    public string ? name {
        get;
        set;
    }
    public string ? brand {
        get;
        set;
    }
    public string ? size {
        get;
        set;
    }
    public decimal price {
        get;
        set;
    }
    public virtual ICollection < Order > orders {
        get;
        set;
    }
}

 

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("order")]
public class Order {
    [Key, Required]
    public int id {
        get;
        set;
    }
    public int product_id {
        get;
        set;
    }
    [Required]
    public string ? name {
        get;
        set;
    }
    public string ? address {
        get;
        set;
    }
    public string ? phone {
        get;
        set;
    }
    public DateTime createdon {
        get;
        set;
    }
    public virtual Product product {
        get;
        set;
    }
}

Step 4

Create EF_DataContext inherited from DbContext class 

using Microsoft.EntityFrameworkCore;
public class EF_DataContext: DbContext {
    public EF_DataContext(DbContextOptions < EF_DataContext > options): base(options) {}
    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        modelBuilder.UseSerialColumns();
    }
    public DbSet <Product> Products {
        get;
        set;
    }
    public DbSet <Order> Orders {
        get;
        set;
    }
}

Step 5

Open appsetting.json

"ConnectionStrings": {
    "Ef_Postgres_Db": "Server=localhost;Database=shopingpostgres;Port=5432;User Id=postgres;Password=qwerty1234;"
}

Step 6

Open Program.cs

builder.Services.AddDbContext < EF_DataContext > (o => o.UseNpgsql(builder.Configuration.GetConnectionString("Ef_Postgres_Db")));

Step 7

Run the 2 commands 

Add-Migration InitialDatabase
Update-Database

Step 8

Create the API Product and Order Models that will be used for API communication

public class Product {
    public int id {
        get;
        set;
    }
    public string ? name {
        get;
        set;
    }
    public string ? brand {
        get;
        set;
    }
    public string ? size {
        get;
        set;
    }
    public decimal price {
        get;
        set;
    }
}
public class Order {
    public int id {
        get;
        set;
    }
    public int product_id {
        get;
        set;
    }
    public string ? name {
        get;
        set;
    }
    public string ? address {
        get;
        set;
    }
    public string ? phone {
        get;
        set;
    }
    public DateTime createdon {
        get;
        set;
    }
    public virtual Product product {
        get;
        set;
    }
}

Step 9

Add the DBhelper class that will talk to your database

using ShoppingWebApi.EfCore;
namespace ShoppingWebApi.Model {
    public class DbHelper {
        private EF_DataContext _context;
        public DbHelper(EF_DataContext context) {
            _context = context;
        }
        /// <summary>
        /// GET
        /// </summary>
        /// <returns></returns>
        public List < ProductModel > GetProducts() {
            List < ProductModel > response = new List < ProductModel > ();
            var dataList = _context.Products.ToList();
            dataList.ForEach(row => response.Add(new ProductModel() {
                brand = row.brand,
                    id = row.id,
                    name = row.name,
                    price = row.price,
                    size = row.size
            }));
            return response;
        }
        public ProductModel GetProductById(int id) {
            ProductModel response = new ProductModel();
            var row = _context.Products.Where(d => d.id.Equals(id)).FirstOrDefault();
            return new ProductModel() {
                brand = row.brand,
                    id = row.id,
                    name = row.name,
                    price = row.price,
                    size = row.size
            };
        }
        /// <summary>
        /// It serves the POST/PUT/PATCH
        /// </summary>
        public void SaveOrder(OrderModel orderModel) {
            Order dbTable = new Order();
            if (orderModel.id > 0) {
                //PUT
                dbTable = _context.Orders.Where(d => d.id.Equals(orderModel.id)).FirstOrDefault();
                if (dbTable != null) {
                    dbTable.phone = orderModel.phone;
                    dbTable.address = orderModel.address;
                }
            } else {
                //POST
                dbTable.phone = orderModel.phone;
                dbTable.address = orderModel.address;
                dbTable.name = orderModel.name;
                dbTable.Product = _context.Products.Where(f => f.id.Equals(orderModel.product_id)).FirstOrDefault();
                _context.Orders.Add(dbTable);
            }
            _context.SaveChanges();
        }
        /// <summary>
        /// DELETE
        /// </summary>
        /// <param name="id"></param>
        public void DeleteOrder(int id) {
            var order = _context.Orders.Where(d => d.id.Equals(id)).FirstOrDefault();
            if (order != null) {
                _context.Orders.Remove(order);
                _context.SaveChanges();
            }
        }
    }
}

Step 10

Create your Api Controller name it as ShoppingRestApi

using Microsoft.AspNetCore.Mvc;
using ShoppingWebApi.EfCore;
using ShoppingWebApi.Model;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace ShoppingWebApi.Controllers {
    [ApiController]
    public class ShoppingApiController: ControllerBase {
        private readonly DbHelper _db;
        public ShoppingApiController(EF_DataContext eF_DataContext) {
            _db = new DbHelper(eF_DataContext);
        }
        // GET: api/<ShoppingApiController>
        [HttpGet]
        [Route("api/[controller]/GetProducts")]
        public IActionResult Get() {
            ResponseType type = ResponseType.Success;
            try {
                IEnumerable < ProductModel > data = _db.GetProducts();
                if (!data.Any()) {
                    type = ResponseType.NotFound;
                }
                return Ok(ResponseHandler.GetAppResponse(type, data));
            } catch (Exception ex) {
                return BadRequest(ResponseHandler.GetExceptionResponse(ex));
            }
        }
        // GET api/<ShoppingApiController>/5
        [HttpGet]
        [Route("api/[controller]/GetProductById/{id}")]
        public IActionResult Get(int id) {
            ResponseType type = ResponseType.Success;
            try {
                ProductModel data = _db.GetProductById(id);
                if (data == null) {
                    type = ResponseType.NotFound;
                }
                return Ok(ResponseHandler.GetAppResponse(type, data));
            } catch (Exception ex) {
                return BadRequest(ResponseHandler.GetExceptionResponse(ex));
            }
        }
        // POST api/<ShoppingApiController>
        [HttpPost]
        [Route("api/[controller]/SaveOrder")]
        public IActionResult Post([FromBody] OrderModel model) {
            try {
                ResponseType type = ResponseType.Success;
                _db.SaveOrder(model);
                return Ok(ResponseHandler.GetAppResponse(type, model));
            } catch (Exception ex) {
                return BadRequest(ResponseHandler.GetExceptionResponse(ex));
            }
        }
        // PUT api/<ShoppingApiController>/5
        [HttpPut]
        [Route("api/[controller]/UpdateOrder")]
        public IActionResult Put([FromBody] OrderModel model) {
            try {
                ResponseType type = ResponseType.Success;
                _db.SaveOrder(model);
                return Ok(ResponseHandler.GetAppResponse(type, model));
            } catch (Exception ex) {
                return BadRequest(ResponseHandler.GetExceptionResponse(ex));
            }
        }
        // DELETE api/<ShoppingApiController>/5
        [HttpDelete]
        [Route("api/[controller]/DeleteOrder/{id}")]
        public IActionResult Delete(int id) {
            try {
                ResponseType type = ResponseType.Success;
                _db.DeleteOrder(id);
                return Ok(ResponseHandler.GetAppResponse(type, "Delete Successfully"));
            } catch (Exception ex) {
                return BadRequest(ResponseHandler.GetExceptionResponse(ex));
            }
        }
    }
}

Step 11

Add the response model and response handler that will handle your API responses

namespace ShoppingWebApi.Model {
    public class ApiResponse {
        public string Code {
            get;
            set;
        }
        public string Message {
            get;
            set;
        }
        public object ? ResponseData {
            get;
            set;
        }
    }
    public enum ResponseType {
        Success,
        NotFound,
        Failure
    }
}

Now test the API's using POSTMAN as shown is video.