Develop REST API-based CRUD Operation using Azure Function and EF Core 7

Introduction

With the help of Azure's Function-based serverless solution, we can develop any type of Application with less code and without any specific hardware infrastructure. Due to this, we also need to spend less money on developing the Application. As Azure's function is supported by the event-driven mechanism, and this can be orchestrated to provide solutions for any type of complex solution.

Azf_EfCore_Api_Banner

In this article, we will discuss how to create an Azure Function-based REST API with the help of an HTTP trigger. This API will communicate with data SQL Server-based database to fetch or save data. For this purpose, we will take the help of Entity Framework Core and demonstrate how we can use EF Core along with Azure Functions to develop any type of REST APIs with less boilerplate-based code.

An Overview of Azure Function

Using Azure Function, we can implement the event-trigger-based automation code implementation without maintaining any infrastructure in the serverless architecture. Once we write down the code for the Azure function, we can directly deploy that code to Azure Resources. There are many benefits of the Azure functions.

  • It supports different languages like C#, JavaScript, F#, PowerShell, and node.js.
  • We can define Azure function for any type of configured trigger like HTTPTrigger, QueueTrigger,  TimerTrigger, etc.
  • We can use the deployment pipeline option like tool based (in Visual Studio or Visual Code), CI/CD, etc.
  • We can use the cross-platform environment for hosting and development.
  • With the help of Application Insights and Azure monitor facility in Azure Portal, we can monitor the performance and issues of the Azure Functions.

Currently, Azure Function provides three different hosting plans.

  • Consumption Plan: This plan is a serverless hosting plan and also supports dynamic scaling features of the resources as per the consumption load. In this plan, it is charged based on resource uses as per the execution numbers, memory consumption, and execution time. 
  • Premium Plan: This plan provides us with unlimited execution duration with 60 minutes duration guarantee. Also, we can use the virtual network connectivity features in this plan. It is charged based on the uses of several core seconds and memory uses within the resources.
  • Dedicated Plan: In this plan, we need to define the computing resources for the execution of the Azure Function.

Entity Framework Core 7

EF Core or Entity Framework Core is based upon the ORM or Object-Relational Mapper model, which supports cross-platform and open source. With the help of this ORM-based model, EF Core helps us to communicate within database objects and application domain models through the intermediate layer. We can consider EF Core as a data access-based API through which we can communicate with database objects with the help of LINQ-type queries and .NET POCOs. At the application level, it always takes less time to implement and develop the entire structure related to the database-related CRUD operations. Entity Framework always helps us to focus mainly on the Application based domain model, and the rest of the database operations are normally taken care of by EF Core itself. With the help of EF Core, we can perform many things.

  • Can fetch data by using C# model class objects with less coding.
  • Can perform all types of CRUD  operations by invoking related methods for those model classes.
  • Can use multiple table objects into a single C# entity object while fetching data.
  • Can use LINQ -based query to fetch data from the database.
  • It supports many different types of databases like SQLite, SQL Server, PostgreSQL, Azure Cosmos DB, etc.
  • Can build and develop our application-based domain model based on any existing database.
  • Can maintain our database schema based on our application domain model.

Create a Database for the CRUD Operations

Before proceeding with developing the Azure function projects, first, we need to create the database and table structure for our example. For that purpose, we are using an SQL Server database. So, we need to create a database name called "AZFCrudDemo". Under that database, we need to create a table name "Employee" with the below comments.

CREATE TABLE[dbo].[Employees](
  [Id][int] IDENTITY(1, 1) NOT NULL,
  [Code][nvarchar](20) NOT NULL,
  [FullName][nvarchar](100) NULL,
  [DOB][datetime] NOT NULL,
  [Address][nvarchar](200) NULL,
  [City][nvarchar](100) NULL,
  [State][nvarchar](100) NULL,
  [Country][nvarchar](100) NULL,
  [PostalCode][nvarchar](15) NULL,
  [EmailId][nvarchar](100) NULL,
  [PhoneNo][nvarchar](50) NULL,
  [JoiningDate][datetime] NULL,
  CONSTRAINT[PK_Employees] PRIMARY KEY CLUSTERED([Id] ASC) ON[PRIMARY]
)

Now, we need to insert one or two records by using the SQL Insert Statement so that while we check our Fetch or Get API, then it can retrieve some data from the database. For this purpose, we can use the below.

Scripts

SET IDENTITY_INSERT[dbo].[Employees] ON
GO
INSERT[dbo].[Employees]([Id], [Code], [FullName], [DOB], [Address], [City], [State], [Country], [PostalCode], [EmailId], [PhoneNo], [JoiningDate]) VALUES(1, N 'A0001', N 'SUMAN SHARMA', CAST(N '1999-10-10T00:00:00.000'
  AS DateTime), N 'ROAD 1', N 'MUMBAI', N 'MAHARASTRA', N 'INDIA', N '400010', N '[email protected]', N '9830098300', CAST(N '2022-02-01T00:00:00.000'
  AS DateTime))
GO
INSERT[dbo].[Employees]([Id], [Code], [FullName], [DOB], [Address], [City], [State], [Country], [PostalCode], [EmailId], [PhoneNo], [JoiningDate]) VALUES(2, N 'A0002', N 'NILAY ROY', CAST(N '1998-05-05T00:00:00.000'
  AS DateTime), N 'ABC', N 'KOLKATA', N 'WB', N 'INDIA', N '700001', N '[email protected]', N '9830198301', CAST(N '2021-10-05T00:00:00.000'
  AS DateTime))
GO
SET IDENTITY_INSERT[dbo].[Employees] OFF
GO

Develop CRUD Operation-based Azure Functions using SQL Client Library

Now, we will demonstrate how we can create an API with the help of the Azure Function using Microsoft Visual Studio 2022. 

Step 1. Open Microsoft Visual Studio 2022 and Select Azure Function Template. After it, click on the Next Button. 

AZF_Template

Step 2. Provide the Project Name and Click on the Next Button.

Step 3. Now, select the Http Trigger Function type from the function dropdown. In this demo, we mainly use the Http Trigger because our target is to create the REST API-based endpoints to perform the CRUD Operations.

AZF_Project

Step 4. Now Click on the Create Button.

Step 5. Now, opens the NuGet Package Manager and install the below-mentioned packages.

  • NewtonSoft.Json
  • System.Data.SqlClient

Step 6. Now create a folder called Model and add a new class called Employee.cs.

Step 7. Now, add the below code in the Employee.cs file.

public class Employee {
  [JsonPropertyName("id")]
  public int Id {
    get;
    set;
  }

  [JsonPropertyName("code")]
  public string Code {
    get;
    set;
  }

  [JsonPropertyName("fullName")]
  public string FullName {
    get;
    set;
  }

  [JsonPropertyName("dateOfBirth")]
  public DateTime DateOfBirth {
    get;
    set;
  }

  public string ? Address {
    get;
    set;
  }
  public string ? City {
    get;
    set;
  }
  public string ? State {
    get;
    set;
  }
  public string ? PostalCode {
    get;
    set;
  }
  public string ? Country {
    get;
    set;
  }
  public string ? PhoneNo {
    get;
    set;
  }
  public string EmailId {
    get;
    set;
  }
  public DateTime JoiningDate {
    get;
    set;
  }
}

Step 8: Now, open the already created function file and add the below code to that file. This part of the code is used to retrieve all records from the Employee Table.

public class FnGetEmployees {
  private readonly ILogger _logger;

  public FnGetEmployees(ILoggerFactory loggerFactory) {
    _logger = loggerFactory.CreateLogger < FnGetEmployees > ();
  }

  [Function("GetEmployees")]
  public async Task < List < Employee >> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "GetEmployees")] HttpRequestData req) {
    var _employee = new List < Employee > ();
    try {
      using(SqlConnection connection = new SqlConnection(Environment.GetEnvironmentVariable("DBConnections"))) {
        connection.Open();
        var query = @ "Select * from Employees";
        SqlCommand command = new SqlCommand(query, connection);
        var reader = await command.ExecuteReaderAsync();
        while (reader.Read()) {
          Employee employee = new Employee() {
            Id = Convert.ToInt32(reader["Id"]),
              Code = Convert.ToString(reader["Code"]),
              FullName = Convert.ToString(reader["FullName"]),
              DateOfBirth = Convert.ToDateTime(reader["DOB"]),
              Address = Convert.ToString(reader["Address"]),
              City = Convert.ToString(reader["City"]),
              State = Convert.ToString(reader["State"]),
              Country = Convert.ToString(reader["Country"]),
              PostalCode = Convert.ToString(reader["PostalCode"]),
              EmailId = Convert.ToString(reader["EmailId"]),
              PhoneNo = Convert.ToString(reader["PhoneNo"]),
              JoiningDate = Convert.ToDateTime(reader["JoiningDate"])
          };
          _employee.Add(employee);
        }
      }
    } catch (Exception e) {
      _logger.LogError(e.ToString());
    }

    return _employee;
  }
}

Step 9. Now, run the applications and check the API Endpoints.

AZF_GetAll

Step 10. Now, simply copy that API End Points and either run it by using any browser (as it is a GET API, we can using paste the URL in the browser and can check the output) or in the Postman.

AZF_GetAll_Postman

Step 11. Now,  Add another new function called FnCreateEmployee and add the below code.

public class FnCreateEmployee {
  private readonly ILogger _logger;

  public FnCreateEmployee(ILoggerFactory loggerFactory) {
    _logger = loggerFactory.CreateLogger < FnCreateEmployee > ();
  }

  [Function("CreateEmployee")]
  public async Task < IActionResult > Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req) {
    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    var _input_data = JsonConvert.DeserializeObject < Employee > (requestBody);

    try {
      using(SqlConnection connection = new SqlConnection(Environment.GetEnvironmentVariable("DBConnections"))) {
        connection.Open();
        if (!string.IsNullOrEmpty(_input_data.Code)) {
          var query = $ "INSERT INTO [dbo].[Employees] ([Code],[FullName],[DOB],[Address],[City],[State],[Country],[PostalCode],[EmailId],[PhoneNo],[JoiningDate]) VALUES (" +
            $ "'{_input_data.Code}'," +
            $ "'{_input_data.FullName}'," +
            $ "'{_input_data.DateOfBirth}'," +
            $ "'{_input_data.Address}'," +
            $ "'{_input_data.City}'," +
            $ "'{_input_data.State}'," +
            $ "'{_input_data.Country}'," +
            $ "'{_input_data.PostalCode}'," +
            $ "'{_input_data.EmailId}'," +
            $ "'{_input_data.PhoneNo}'," +
            $ "'{_input_data.JoiningDate}')";
          SqlCommand command = new SqlCommand(query, connection);
          command.ExecuteNonQuery();
        }
      }
    } catch (Exception e) {
      _logger.LogError(e.ToString());
      return new ObjectResult(e.ToString());
    }
    return new OkObjectResult(HttpStatusCode.OK);
  }
}

Step 12: Now, run the Application and execute the Create Employee endpoints from the Postman.

AZF_Create_Emp

Implement EF Core 7 within the Azure Functions 

Now, in the above example, we used SqlDataClient to communicate with the SQL Server database to retrieve or save operations. Now, in this part, we will use the Entity Framework Core 7.0 for the same purpose. So, for that purpose, first, we need to install the Entity Framework Core-related NuGet Packages from NuGet Package Manager – 

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools

Now, after installing the above nuget packages, Create a folder called DataAccessLayer, and then within that folder, add a new file called SQLDBContext and add the below code there.

public partial class SQLDBContext: DbContext {
  public SQLDBContext() {}

  public SQLDBContext(DbContextOptions < SQLDBContext > options): base(options) {}

  public virtual DbSet < Employee > Employees {
    get;
    set;
  }

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {

  }

  protected override void OnModelCreating(ModelBuilder modelBuilder) {

  }
}

Now, open the already existing FnGetEmployees function and replace the existing code with the below one.

public class FnGetEmployees {
  private readonly ILogger _logger;
  private readonly HttpClient _httpClient;

  public FnGetEmployees(ILoggerFactory loggerFactory) {
    _logger = loggerFactory.CreateLogger < FnGetEmployees > ();
  }

  [Function("GetEmployees")]
  public async Task < List < Employee >> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "GetEmployees")] HttpRequestData req) {
    var _employee = new List < Employee > ();
    try {
      string defaultConnection = Environment.GetEnvironmentVariable("DBConnections");

      _logger.LogInformation(defaultConnection);
      var options = new DbContextOptionsBuilder < SQLDBContext > ();
      options.UseSqlServer(defaultConnection);

      var _dbContext = new SQLDBContext(options.Options);

      _employee = await _dbContext.Employees.ToListAsync();
    } catch (Exception e) {
      _logger.LogError(e.ToString());
    }

    return _employee;
  }
}

Now, in the same way, will change the implementation of Employee Create functions as below.

public class FnCreateEmployee {
  private readonly ILogger _logger;

  public FnCreateEmployee(ILoggerFactory loggerFactory) {
    _logger = loggerFactory.CreateLogger < FnCreateEmployee > ();
  }

  [Function("CreateEmployee")]
  public async Task < IActionResult > Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req) {
    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    var _input_data = JsonConvert.DeserializeObject < Employee > (requestBody);

    try {

      string defaultConnection = Environment.GetEnvironmentVariable("DBConnections");
      var options = new DbContextOptionsBuilder < SQLDBContext > ();
      options.UseSqlServer(defaultConnection);

      var _dbContext = new SQLDBContext(options.Options);

      _dbContext.Employees.Add(_input_data);
      await _dbContext.SaveChangesAsync();

    } catch (Exception e) {
      _logger.LogError(e.ToString());
      return new ObjectResult(e.ToString());
    }
    return new OkObjectResult(HttpStatusCode.OK);
  }
}

Now, we can use the Application and test the API endpoints by using Postman.

Conclusion

This article discusses how to develop REST APIs for CRUD operations using Azure Function. Also, we discussed the steps related to the implementation of Entity Framework Core 7 in Azure Function. Any suggestions, feedback, or queries related to this article are welcome.