<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ MinimalApi - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ MinimalApi - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 24 Jun 2026 22:47:24 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/minimalapi/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Minimal API in .NET Core – A Step By Step Handbook ]]>
                </title>
                <description>
                    <![CDATA[ Minimal APIs are an exciting feature introduced in .NET 6, designed to revolutionize how you create APIs. Imagine building robust APIs with minimal code and zero boilerplate—no more wrestling with controllers, routing, or middleware. That’s what mini... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-a-minimal-api-in-net-core-handbook/</link>
                <guid isPermaLink="false">674de68794b89afe5676934e</guid>
                
                    <category>
                        <![CDATA[ dotnet ]]>
                    </category>
                
                    <category>
                        <![CDATA[ .NET ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MinimalApi ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Isaiah Clifford Opoku ]]>
                </dc:creator>
                <pubDate>Mon, 02 Dec 2024 16:55:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733158500882/9af04a12-2121-4efd-a66f-00330896e358.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Minimal APIs are an exciting feature introduced in .NET 6, designed to revolutionize how you create APIs.</p>
<p>Imagine building robust APIs with minimal code and zero boilerplate—no more wrestling with controllers, routing, or middleware. That’s what minimal APIs allow you to do. The idea with these APIs is to streamline the development process, making it incredibly easy and efficient.</p>
<p>In this article, we'll dive into the world of minimal APIs in .NET 8 and guide you through creating a fully functional bookstore API. You'll learn how to get all books, retrieve a book by its ID, add new books, and even delete books. Let’s get started.</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-introduction-to-minimal-apis">Introduction to Minimal APIs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-minimal-api">How to Create a Minimal API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-http-methods-in-controller-based-and-minimal-apis">HTTP Methods in Controller-based and Minimal APIs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-minimal-api-project-files">Minimal API Project Files</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-models">How to Create the Models</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-database-context">How to Create the Database Context</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-contract">How to Create a Contract</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-services">How to Add Services</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-exceptions">How to Create Exceptions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-api-endpoints">How to Create the API Endpoints</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-seed-data-to-the-database">How to Add Seed Data to the Database</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-perform-a-migration">How to Perform a Migration</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-the-api-endpoints">How to Test the API Endpoints</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we get going, make sure you have the following prerequisites installed on your machine:</p>
<ul>
<li><p><a target="_blank" href="https://dotnet.microsoft.com/download/dotnet/8.0">.NET 8 SDK</a></p>
</li>
<li><p><a target="_blank" href="https://code.visualstudio.com/download">Visual Studio Code</a> or any other code editor of your choice</p>
</li>
<li><p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp">C# Dev Kit</a> for Visual Studio Code</p>
</li>
</ul>
<p>Alternatively, you can use Visual Studio 2022, which comes with built-in support for .NET 8. But in this article, we'll be using Visual Studio Code. It’s lightweight, easy to use, and cross-platform.</p>
<p>We’ll use Swagger UI to test our API. Swagger UI is a powerful tool that allows you to interact with your API directly from your browser. It provides a user-friendly interface to test your API endpoints, making it easier to test and debug your API.</p>
<p>When you create a new project, it will automatically install the necessary packages and configure the project to use Swagger UI. .NET 8 includes Swagger UI by default, so whether you create your application in Visual Studio or with .NET, Swagger UI will be configured for you.</p>
<p>Run your application, and the Swagger UI will automatically open in your browser – but since we are using VS Code, we need to click on the port number on our terminal.</p>
<p>You can find the source code for this project on <a target="_blank" href="https://github.com/Clifftech123/bookapi-minimal">GitHub</a>.</p>
<h2 id="heading-introduction-to-minimal-apis">Introduction to Minimal APIs</h2>
<p>Imagine working in a codebase with numerous endpoints, making it quite large and complex. Traditionally, building an API in <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core involves using controllers, routing, middleware, and a significant amount of boilerplate code. But there are two approaches to building an API in ASP.NET Core: the traditional way and the minimal way.</p>
<p>The traditional way is familiar to most developers, involving controllers and extensive infrastructure code. The minimal way, introduced in <code>.NET 6</code>, allows you to create APIs with minimal code and zero boilerplate. This approach simplifies the development process, enabling you to focus on writing business logic rather than dealing with infrastructure code.</p>
<p>Minimal APIs are lightweight, fast, and perfect for building small to medium-sized APIs. They are ideal for prototyping, building microservices, or creating simple APIs that don't require much complexity. In this handbook, we'll explore the world of minimal APIs in .NET 6 and learn how to create a fully functional bookstore API from scratch.</p>
<h2 id="heading-how-to-create-a-minimal-api">How to Create a Minimal API</h2>
<p>Creating a minimal API is straightforward when using the <code>dotnet CLI</code>, as the default template is already a minimal API. But if you use Visual Studio, you'll need to remove the boilerplate code that comes with the project template.</p>
<p>Let's start by using the <code>dotnet CLI</code> to create a minimal API project.</p>
<pre><code class="lang-bash">
dotnet new webapi  -n BookStoreApi
</code></pre>
<p>The <code>dotnet new webapi</code> command creates a new minimal API project named <code>BookStoreApi</code>. This project contains the necessary files and folders to get you started.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732623879052/3db8614b-7b27-43ce-ad84-9fa66001b535.png" alt="Minimal API Project Files   Structure  " width="2556" height="1370" loading="lazy"></p>
<p>Let's explore the project structure:</p>
<ul>
<li><p><code>Program.cs</code>: The entry point of the application, where the host is configured.</p>
</li>
<li><p><code>bookapi-minimal.sln</code>: The solution file that contains the project.</p>
</li>
<li><p><code>bookapi-minimal.http</code>: A file that contains sample HTTP requests to test the API.</p>
</li>
<li><p><code>bookapi-minimal.csproj</code>: The project file that contains the project configuration.</p>
</li>
<li><p><code>appsettings.json</code>: The configuration file that stores application settings.</p>
</li>
<li><p><code>appsettings.Development.json</code> : The configuration file for the development environment.</p>
</li>
</ul>
<p>When you open the program.cs file, you'll notice that the code is minimal. The <code>Program.cs</code> file contains the following code:</p>
<pre><code class="lang-csharp">
<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

<span class="hljs-comment">// Add services to the container.</span>
<span class="hljs-comment">// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle</span>
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-comment">// Configure the HTTP request pipeline.</span>
<span class="hljs-keyword">if</span> (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

<span class="hljs-keyword">var</span> summaries = <span class="hljs-keyword">new</span>[]
{
    <span class="hljs-string">"Freezing"</span>, <span class="hljs-string">"Bracing"</span>, <span class="hljs-string">"Chilly"</span>, <span class="hljs-string">"Cool"</span>, <span class="hljs-string">"Mild"</span>, <span class="hljs-string">"Warm"</span>, <span class="hljs-string">"Balmy"</span>, <span class="hljs-string">"Hot"</span>, <span class="hljs-string">"Sweltering"</span>, <span class="hljs-string">"Scorching"</span>
};

app.MapGet(<span class="hljs-string">"/weatherforecast"</span>, () =&gt;
{
    <span class="hljs-keyword">var</span> forecast =  Enumerable.Range(<span class="hljs-number">1</span>, <span class="hljs-number">5</span>).Select(index =&gt;
        <span class="hljs-keyword">new</span> WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(<span class="hljs-number">-20</span>, <span class="hljs-number">55</span>),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    <span class="hljs-keyword">return</span> forecast;
})
.WithName(<span class="hljs-string">"GetWeatherForecast"</span>)
.WithOpenApi();

app.Run();

<span class="hljs-keyword">record</span> <span class="hljs-title">WeatherForecast</span>(<span class="hljs-title">DateOnly</span> <span class="hljs-title">Date</span>, <span class="hljs-title">int</span> <span class="hljs-title">TemperatureC</span>, <span class="hljs-title">string</span>? <span class="hljs-title">Summary</span>)
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> TemperatureF =&gt; <span class="hljs-number">32</span> + (<span class="hljs-keyword">int</span>)(TemperatureC / <span class="hljs-number">0.5556</span>);
}
</code></pre>
<p>If you don't fully understand the code yet, don't worry—we'll cover it in detail in the upcoming sections. The key takeaway is that minimal APIs require very little code, which is one of their main advantages.</p>
<p>The default code sets up a simple weather forecast API that you can use to test your setup. It generates a list of weather forecasts and returns them when you make a <code>GET</code> request to the <code>/weatherforecast</code> endpoint. Also, the code includes Swagger UI to help you test the API.</p>
<p>Pay special attention to the <code>app.MapGet</code> method, which maps a route to a handler function. In this case, it maps the <code>/weatherforecast</code> route to a function that returns a list of weather forecasts. We'll use similar methods to create our own endpoints in the next sections.</p>
<p>Before we start creating our project folder structure, let's understand the HTTP methods in both Controller-based and Minimal APIs.</p>
<h2 id="heading-http-methods-in-controller-based-and-minimal-apis">HTTP Methods in Controller-based and Minimal APIs</h2>
<p>In a Controller-based approach, which is the traditional way of creating web APIs, you need to create a controller class and define methods for each HTTP method. For example:</p>
<ul>
<li><p>To create a <code>GET</code> method, you use the <code>[HttpGet]</code> attribute.</p>
</li>
<li><p>To create a <code>POST</code> method, you use the <code>[HttpPost]</code> attribute.</p>
</li>
<li><p>To create a <code>PUT</code> method, you use the <code>[HttpPut]</code> attribute.</p>
</li>
<li><p>To create a <code>DELETE</code> method, you use the <code>[HttpDelete]</code> attribute.</p>
</li>
</ul>
<p>This is how endpoints are created in a Controller-based approach.</p>
<p>In contrast, Minimal APIs use methods like <code>app.MapGet</code>, <code>app.MapPost</code>, <code>app.MapPut</code>, and <code>app.MapDelete</code> to create endpoints. This is the main difference between the two approaches: Controller-based APIs use attributes to define endpoints, while Minimal APIs use methods.</p>
<p>Now that you understand how to handle HTTP requests in both Controller-based and Minimal APIs, let's create our project folder structure.</p>
<p>Before we create our project folder structure, let's first run what we have. As we learned earlier, when you create a project with either Visual Studio or .NET CLI, it comes with a default WeatherForecast project which we can run and see on the UI. Let's run it to ensure everything works before we go on to create our project folder.</p>
<p>Run this command:</p>
<pre><code class="lang-bash">
dotnet run
</code></pre>
<p>You should see the following output:</p>
<pre><code class="lang-bash">info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5228
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: D:\Devolopemnt\Dotnet\bookapi-minimal
</code></pre>
<p>This means the application is running and listening on <a target="_blank" href="http://localhost:5228"><code>http://localhost:5228</code></a>. As I mentioned above, since we are using the <code>dotnet CLI</code> and Visual Studio Code, the application will not automatically open the browser for us. We need to do this manually.</p>
<p>Open your browser and navigate to <a target="_blank" href="http://localhost:5228/swagger/index.html"><code>http://localhost:5228/swagger/index.html</code></a> to see the default response from the API.</p>
<p>You should see something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732623894640/b882a1ee-3957-4958-8f59-20b44fe7fb7d.png" alt="Swagger UI " width="2436" height="1169" loading="lazy"></p>
<p>Now the next thing for us to do is find a way to structure our project and create the necessary files and folders to get us started.</p>
<h2 id="heading-minimal-api-project-files">Minimal API Project Files</h2>
<p>To organize our project, we will create a structured folder hierarchy. This will help keep our code clean and maintainable. Here is the folder structure we will use:</p>
<ul>
<li><p><strong>AppContext</strong>: Contains the database context and related configurations.</p>
</li>
<li><p><strong>Configurations</strong>: Holds Entity Framework Core configurations and seed data for the database.</p>
</li>
<li><p><strong>Contracts</strong>: Contains Data Transfer Objects (DTOs) used in our application.</p>
</li>
<li><p><strong>Endpoints</strong>: Where we define and configure our minimal API endpoints.</p>
</li>
<li><p><strong>Exceptions</strong>: Contains custom exception classes used in the project.</p>
</li>
<li><p><strong>Extensions</strong>: Holds extension methods that we will use throughout the project.</p>
</li>
<li><p><strong>Models</strong>: Contains business logic models.</p>
</li>
<li><p><strong>Services</strong>: Contains service classes that implement business logic.</p>
</li>
<li><p><strong>Interfaces</strong>: Holds interface definitions used to map our services.</p>
</li>
</ul>
<p>In Visual Studio Code, you can create this folder structure as follows:</p>
<pre><code class="lang-bash">- AppContext
- Configurations
- Contracts
- Endpoints
- Exceptions
- Extensions
- Models
- Services
- Interfaces
</code></pre>
<p>After setting up, your project folder structure should look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732623997951/8118c444-0d28-4bb7-8cad-2a9fd88c8c25.png" alt="BookApi Project Folder Structure " width="1920" height="890" loading="lazy"></p>
<p>Now that our project Structure is set up we can go ahead and start writing our code. Let's start by creating our models.</p>
<h2 id="heading-how-to-create-the-models">How to Create the Models</h2>
<p>In this section, we will create models for our application. Models are the building blocks of our application, representing the data that our application will work with. For our example, we will create a model for a book.</p>
<p>To get started, create a folder named <code>Models</code> in your project directory. Inside this folder, create a file named <code>BookModel.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Models/BookModel.cs</span>


<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Models</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookModel</span>
    {
        <span class="hljs-keyword">public</span> Guid Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Author { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Category { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Language { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> TotalPages { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<p>This <code>BookModel class</code> defines the properties that represent the details of a book, such as its <code>title</code>, <code>author</code>, <code>description</code>, <code>category</code>, <code>language</code>, and <code>total pages</code>. Each property is designed to hold specific information about the book, making it easy to manage and manipulate book data within our application.</p>
<p>Now that we have created our model, let's create our database context.</p>
<h2 id="heading-how-to-create-the-database-context">How to Create the Database Context</h2>
<p>The database context is a class that represents a session with the database. It’s responsible for interacting with the database and executing database operations. In our application, we will use Entity Framework Core to interact with our database.</p>
<h3 id="heading-install-the-required-packages">Install the Required Packages</h3>
<p>Before creating our database context, we need to install the following packages:</p>
<ul>
<li><p><a target="_blank" href="http://Microsoft.EntityFrameworkCore.Design"><code>Microsoft.EntityFrameworkCore.Design</code></a></p>
</li>
<li><p><code>Microsoft.EntityFrameworkCore</code></p>
</li>
<li><p><code>Microsoft.EntityFrameworkCore.SqlServer</code></p>
</li>
<li><p><a target="_blank" href="http://Microsoft.EntityFrameworkCore.Tools"><code>Microsoft.EntityFrameworkCore.Tools</code></a></p>
</li>
<li><p><code>FluentValidation.DependencyInjectionExtensions</code></p>
</li>
</ul>
<p>You can install these packages using the following commands:</p>
<pre><code class="lang-bash">dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package FluentValidation.DependencyInjectionExtensions
</code></pre>
<h3 id="heading-verify-package-installation">Verify Package Installation</h3>
<p>To verify that the packages are installed, open the <code>bookapi-minimal.csproj</code> file in your project's root directory. You should see the installed packages listed as follows:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Project</span> <span class="hljs-attr">Sdk</span>=<span class="hljs-string">"Microsoft.NET.Sdk.Web"</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TargetFramework</span>&gt;</span>net8.0<span class="hljs-tag">&lt;/<span class="hljs-name">TargetFramework</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Nullable</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">Nullable</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ImplicitUsings</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">ImplicitUsings</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">RootNamespace</span>&gt;</span>bookapi_minimal<span class="hljs-tag">&lt;/<span class="hljs-name">RootNamespace</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">ItemGroup</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"FluentValidation.DependencyInjectionExtensions"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"11.9.2"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.AspNetCore.OpenApi"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.6"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.Design"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag">&lt;/<span class="hljs-name">IncludeAssets</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">PrivateAssets</span>&gt;</span>all<span class="hljs-tag">&lt;/<span class="hljs-name">PrivateAssets</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">PackageReference</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.SqlServer"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.Tools"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag">&lt;/<span class="hljs-name">IncludeAssets</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">PrivateAssets</span>&gt;</span>all<span class="hljs-tag">&lt;/<span class="hljs-name">PrivateAssets</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">PackageReference</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Swashbuckle.AspNetCore"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"6.4.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ItemGroup</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">Project</span>&gt;</span>
</code></pre>
<p>This confirms that the packages have been successfully installed.</p>
<p>Now let's create our database context.</p>
<p>In the AppContext folder, create a new file named <code>ApplicationContext.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// AppContext/ApplicationContext.cs</span>

<span class="hljs-keyword">using</span> bookapi_minimal.Models;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.AppContext</span>
{

    <span class="hljs-function"><span class="hljs-keyword">public</span> class <span class="hljs-title">ApplicationContext</span>(<span class="hljs-params">DbContextOptions&lt;ApplicationContext&gt; options</span>) : <span class="hljs-title">DbContext</span>(<span class="hljs-params">options</span>)</span>
    {

        <span class="hljs-comment">// Default schema for the database context</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> DefaultSchema = <span class="hljs-string">"bookapi"</span>;


       <span class="hljs-comment">// DbSet to represent the collection of books in our database</span>
        <span class="hljs-keyword">public</span> DbSet&lt;BookModel&gt; Books { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-comment">// Constructor to configure the database context</span>

        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnModelCreating</span>(<span class="hljs-params">ModelBuilder modelBuilder</span>)</span>
        {
            <span class="hljs-keyword">base</span>.OnModelCreating(modelBuilder);
            modelBuilder.HasDefaultSchema(DefaultSchema);

            modelBuilder.ApplyConfigurationsFromAssembly(<span class="hljs-keyword">typeof</span>(ApplicationContext).Assembly);

            modelBuilder.ApplyConfigurationsFromAssembly(<span class="hljs-keyword">typeof</span>(ApplicationContext).Assembly);

        }

    }
}
</code></pre>
<p>Let's break down the code above:</p>
<ul>
<li><p>We define a class named <code>ApplicationContext</code> that inherits from <code>DbContext</code>. The <code>DbContext</code> class is part of Entity Framework Core and represents a session with the database.</p>
</li>
<li><p>The constructor accepts an instance of <code>DbContextOptions&lt;ApplicationContext&gt;</code>. This constructor is used to configure the database context options.</p>
</li>
<li><p>We define a property named <code>Books</code> type <code>DbSet&lt;BookModel&gt;</code>. This property represents the collection of books in our database.</p>
</li>
<li><p>We override the <code>OnModelCreating</code> method to configure the database schema and apply any configurations defined in our application.</p>
</li>
</ul>
<p>Now that we have created our database context, let's create our extension method and register our database context in the dependency injection container.</p>
<h3 id="heading-create-an-extension-method">Create an Extension Method</h3>
<p>Before we create the extension method, let's understand what an extension method is in the context of <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core.</p>
<p>An extension method is a static method that adds new functionality to an existing type without modifying the original type. In <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core, extension methods are commonly used to extend the functionality of the <code>IServiceCollection</code> interface, which is used to register services in the dependency injection container.</p>
<p>Services are components that provide functionality to an application, such as database access, logging, and configuration. By creating an extension method for the <code>IServiceCollection</code> interface, you can simplify the process of registering your services in the dependency injection container.</p>
<p>Instead of putting everything in the <code>Program.cs</code> file, we will create an extension method to register our services in the dependency injection container. This will help us keep our code clean and organized.</p>
<p>In the <code>Extensions</code> folder, create a new file named <code>ServiceExtensions.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Reflection;
<span class="hljs-keyword">using</span> bookapi_minimal.AppContext;
<span class="hljs-keyword">using</span> FluentValidation;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Extensions</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ServiceExtensions</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddApplicationServices</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IHostApplicationBuilder builder</span>)</span>
        {
            <span class="hljs-keyword">if</span> (builder == <span class="hljs-literal">null</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(builder));
            <span class="hljs-keyword">if</span> (builder.Configuration == <span class="hljs-literal">null</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(builder.Configuration));

            <span class="hljs-comment">// Adding the database context</span>
            builder.Services.AddDbContext&lt;ApplicationContext&gt;(configure =&gt;
            {
                configure.UseSqlServer(builder.Configuration.GetConnectionString(<span class="hljs-string">"sqlConnection"</span>));
            });

            <span class="hljs-comment">// Adding validators from the current assembly</span>
            builder.Services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
        }
    }
}
</code></pre>
<p>Let's break down the code above:</p>
<ul>
<li><p>We define a static class named <code>ServiceExtensions</code> that contains an extension method named <code>AddApplicationServices</code>. This method extends the <code>IHostApplicationBuilder</code> interface, which is used to configure the application's request processing pipeline.</p>
</li>
<li><p>The <code>AddApplicationServices</code> method accepts an instance of <code>IHostApplicationBuilder</code> as a parameter. This parameter is used to access the application's configuration and services.</p>
</li>
<li><p>We add the <code>ApplicationContext</code> to the dependency injection container and configure it to use SQL Server as the database provider. We retrieve the connection string from the <code>appsettings.json</code> file using the <code>GetConnectionString</code> method.</p>
</li>
<li><p>We add <code>validators</code> from the current <code>assembly</code> using the <code>AddValidatorsFromAssembly</code> method. This method scans the current assembly for classes that implement the IValidator interface and registers them in the dependency injection container.</p>
</li>
</ul>
<p>Next, we need to add the connection string to the <code>appsettings.json</code> file. Add the following code to your <code>appsettings.json</code> file:</p>
<pre><code class="lang-json">{ 
     <span class="hljs-attr">"ConnectionStrings"</span>: {
    <span class="hljs-attr">"sqlConnection"</span>: <span class="hljs-string">"Server=localhost\\SQLEXPRESS02;Database=BookAPIMinimalAPI;Integrated Security=true;TrustServerCertificate=true;"</span>
  }
  }
</code></pre>
<p>Make sure to replace <code>your_password</code> it with your actual SQL Server password.</p>
<p>Your <code>appsettings.json</code> file should look like this:</p>
<pre><code class="lang-json">
{
  <span class="hljs-attr">"Logging"</span>: {
    <span class="hljs-attr">"LogLevel"</span>: {
      <span class="hljs-attr">"Default"</span>: <span class="hljs-string">"Information"</span>,
      <span class="hljs-attr">"Microsoft.AspNetCore"</span>: <span class="hljs-string">"Warning"</span>
    }
  },
  <span class="hljs-attr">"ConnectionStrings"</span>: {
    <span class="hljs-attr">"sqlConnection"</span>: <span class="hljs-string">"Server=localhost\\SQLEXPRESS02;Database=BookAPIMinimalAPI;Integrated Security=true;TrustServerCertificate=true;"</span>
  },
  <span class="hljs-attr">"AllowedHosts"</span>: <span class="hljs-string">"*"</span>
}
</code></pre>
<p>Congratulations! You have successfully created the database context, extension method, and connection string for your application. In the next section, we will create a Contract.</p>
<h2 id="heading-how-to-create-a-contract">How to Create a Contract</h2>
<p>Contracts are Data Transfer Objects (DTOs) that define the structure of the data exchanged between the client and the server. In our application, we will create contracts to represent the data sent and received by our API endpoints.</p>
<p>Here are the contracts we are going to create:</p>
<ul>
<li><p>CreateBookRequest: This represents the data sent when creating a new book.</p>
</li>
<li><p>UpdateBookRequest: tHI Represents the data sent when updating an existing book.</p>
</li>
<li><p>BookResponse: Represents the data returned when retrieving a book.</p>
</li>
<li><p>ErrorResponse: Represents the error response returned when an exception occurs.</p>
</li>
<li><p>ApiResponse: Represents the response returned by the API.</p>
</li>
</ul>
<p>In the <code>Contracts</code> folder, create a new file named <code>CreateBookRequest</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Contracts/CreateBookRequest.cs</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Contracts</span>
{

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">CreateBookRequest</span>
    { 

        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Author { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Category { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Language { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> TotalPages { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }
    }
}
</code></pre>
<p>In the <code>Contracts</code> folder, create a new file named <code>UpdateBookRequest</code> and add the following code:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Contracts/UpdateBookRequest.cs</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Contracts</span>
{

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">UpdateBookRequest</span>
    {
       <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Author { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Category { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Language { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> TotalPages { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    }
}
</code></pre>
<p>In the <code>Contracts</code> folder, create a new file named <code>BookResponse</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Contracts/BookResponse.cs</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Contracts</span>
{

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">BookResponse</span>
    {
        <span class="hljs-keyword">public</span> Guid Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Author { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Category { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Language { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> TotalPages { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<p>In the <code>Contracts</code> folder, create a new file named <code>ErrorResponse</code> and add the following code:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Contracts/ErrorResponse.cs</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Contracts</span>
{

        <span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">ErrorResponse</span>
    {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> StatusCode { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Message { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    }

}
</code></pre>
<p>In the <code>Contracts</code> folder, create a new file named <code>ApiResponse</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Contracts/ApiResponse.cs</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Contracts</span>
{

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ApiResponse</span>&lt;<span class="hljs-title">T</span>&gt;
    {
        <span class="hljs-keyword">public</span> T Data { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Message { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ApiResponse</span>(<span class="hljs-params">T data, <span class="hljs-keyword">string</span> message</span>)</span>
        {
            Data = data;
            Message = message;
        }
    }
}
</code></pre>
<p>These contracts help us define the structure of the data exchanged between the client and the server, making it easier to work with the data in our application.</p>
<p>In the next section, we will create services to implement the business logic of our application.</p>
<h2 id="heading-how-to-add-services">How to Add Services</h2>
<p>Services are components that provide functionality to an application. In our application, we will create services to implement the business logic of our application. We will create services to handle CRUD operations for books, validate book data, and handle exceptions.</p>
<p>In ASP.NET Core, services are registered in the dependency injection container and can be injected into other components, such as controllers and endpoints, But this is a minimal API so we will inject the services directly into the endpoints.</p>
<p>Let's create an interface for our services. In the <code>Interfaces</code> folder, create a new file named <code>IBookService.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"> <span class="hljs-comment">// Interfaces/IBookService.cs</span>



<span class="hljs-keyword">using</span> bookapi_minimal.Contracts;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Interfaces</span>
{
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IBookService</span>
    {
        <span class="hljs-function">Task&lt;BookResponse&gt; <span class="hljs-title">AddBookAsync</span>(<span class="hljs-params">CreateBookRequest createBookRequest</span>)</span>;
        <span class="hljs-function">Task&lt;BookResponse&gt; <span class="hljs-title">GetBookByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>;
        Task&lt;IEnumerable&lt;BookResponse&gt;&gt; GetBooksAsync();
        <span class="hljs-function">Task&lt;BookResponse&gt; <span class="hljs-title">UpdateBookAsync</span>(<span class="hljs-params">Guid id,  UpdateBookRequest  updateBookRequest</span>)</span>;
        <span class="hljs-function">Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">DeleteBookAsync</span>(<span class="hljs-params">Guid id</span>)</span>;
    }
}
</code></pre>
<p>Let's break down the code above: We have defined an interface named <code>IBookService</code> that contains methods to handle CRUD operations for books. The interface defines the following methods:</p>
<ul>
<li><p><code>AddBookAsync</code>: Adds a new book to the database.</p>
</li>
<li><p><code>GetBookByIdAsync</code>: Retrieves a book by its ID.</p>
</li>
<li><p><code>GetBooksAsync</code>: Retrieves all books from the database.</p>
</li>
<li><p><code>UpdateBookAsync</code>: Updates an existing book.</p>
</li>
</ul>
<p>We are using the Contract we created earlier in the <code>Contracts</code> folder. The <code>IBookService</code> interface defines the structure of the methods that will be implemented by the service classes. This helps us separate the interface from the implementation, making it easier to maintain and test our code.</p>
<p>Now that we have created the interface, let's create the service class that implements the interface.</p>
<h3 id="heading-how-to-implement-the-book-service">How to Implement the Book Service</h3>
<p>This service will implement the <code>IBookService</code> interface and provide the business logic for our application. In the <code>Services</code> folder, create a new file named <code>BookService.cs</code> . Your initial file should look like this:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Services/BookService.cs</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookService</span>
    {

    }
}
</code></pre>
<p>The first thing we need to do is add the interface to the <code>BookService</code> class. Update the <code>BookService</code> class to implement the <code>IBookService</code> interface as follows:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Services/BookService.cs</span>



<span class="hljs-keyword">using</span> bookapi_minimal.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookService</span>:<span class="hljs-title">IBookService</span>
    {

    }
}
</code></pre>
<p>When you do this, your VS Code might show an error because we have not implemented the methods in the interface. Let's go ahead and implement the methods in the <code>BookService</code> class.</p>
<p>In VS Code you can use the <code>Ctrl + .</code> shortcut to implement the methods in the interface. Then you will see the following code generated for you:</p>
<pre><code class="lang-csharp">
<span class="hljs-keyword">using</span> bookapi_minimal.Contracts;
<span class="hljs-keyword">using</span> bookapi_minimal.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Services</span>
{
     <span class="hljs-comment">// Service class for managing books</span>
   <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookService</span> : <span class="hljs-title">IBookService</span>
   {
       <span class="hljs-comment">// Method to add a new book to the database</span>
       <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;BookResponse&gt; <span class="hljs-title">AddBookAsync</span>(<span class="hljs-params">CreateBookRequest createBookRequest</span>)</span>
       {
           <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
       }

      <span class="hljs-comment">// Method to Delete a book from the database</span>
       <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">DeleteBookAsync</span>(<span class="hljs-params">Guid id</span>)</span>
       {
           <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
       }

       <span class="hljs-comment">// Method to Get a book from the database by its ID</span>

       <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;BookResponse&gt; <span class="hljs-title">GetBookByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
       {
           <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
       }

      <span class="hljs-comment">// Method to Get all books from the database</span>
       <span class="hljs-keyword">public</span> Task&lt;IEnumerable&lt;BookResponse&gt;&gt; GetBooksAsync()
       {
           <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
       }

       <span class="hljs-comment">// Method to Update a book in the database</span>
       <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;BookResponse&gt; <span class="hljs-title">UpdateBookAsync</span>(<span class="hljs-params">Guid id, UpdateBookRequest updateBookRequest</span>)</span>
       {
           <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
       }
   }
}
</code></pre>
<p>Now you can see that the methods in the interface have been implemented in the <code>BookService</code> class. We will implement the business logic for each method in the next section.</p>
<p>Before we do that, let's add the necessary dependencies to the <code>BookService</code> class. We need to inject the <code>ApplicationContext</code> and <code>ILogger</code> dependencies into the <code>BookService</code> class. <code>ApplicationContext</code> is used to interact with the database, while <code>ILogger</code> is used for logging.</p>
<p>To inject the dependencies, update the <code>BookService</code> class as follows:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Services/BookService.cs</span>

<span class="hljs-comment">// ...</span>
 <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ApplicationContext _context; <span class="hljs-comment">// Database context</span>
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;BookService&gt; _logger; <span class="hljs-comment">// Logger for logging information and errors</span>

<span class="hljs-comment">//..</span>
</code></pre>
<p>Since we have added the dependencies, we need to update the <code>BookService</code> constructor to accept the dependencies. Update the <code>BookService</code> constructor as follows:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Services/BookService.cs</span>

<span class="hljs-comment">// ...</span>

  <span class="hljs-comment">// Constructor to initialize the database context and logger</span>
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BookService</span>(<span class="hljs-params">ApplicationContext context, ILogger&lt;BookService&gt; logger</span>)</span>
 {
            _context = context;
            _logger = logger;
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Now that we have added the dependencies and updated the constructor, we can implement the business logic for each method in the <code>BookService</code> class.</p>
<p>Let's create logic for the CREATE, READ, UPDATE, and DELETE operations in the <code>BookService</code> class.</p>
<h3 id="heading-how-to-implement-the-addbookasync-method">How to Implement the <code>AddBookAsync</code> Method</h3>
<p>As I mentioned earlier, we’ll use the <code>AddBookAsync</code> method to add a new book to the database. In this method, we will create a new book entity, map the data from the <code>CreateBookRequest</code> object to the book entity, and save the book entity to the database. We will also return the book entity as an <code>BookResponse</code> object.</p>
<p>Update the <code>AddBookAsync</code> method in the <code>BookService</code> class as follows:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/BookService.cs</span>

<span class="hljs-comment">// ...</span>
 <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Add a new book</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="createBookRequest"&gt;</span>Book request to be added<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>Details of the created book<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;BookResponse&gt; <span class="hljs-title">AddBookAsync</span>(<span class="hljs-params">CreateBookRequest createBookRequest</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> book = <span class="hljs-keyword">new</span> BookModel
                {
                    Title = createBookRequest.Title,
                    Author = createBookRequest.Author,
                    Description = createBookRequest.Description,
                    Category = createBookRequest.Category,
                    Language = createBookRequest.Language,
                    TotalPages = createBookRequest.TotalPages
                };

                <span class="hljs-comment">// Add the book to the database</span>
                _context.Books.Add(book);
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
                _logger.LogInformation(<span class="hljs-string">"Book added successfully."</span>);

                <span class="hljs-comment">// Return the details of the created book</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = book.Id,
                    Title = book.Title,
                    Author = book.Author,
                    Description = book.Description,
                    Category = book.Category,
                    Language = book.Language,
                    TotalPages = book.TotalPages
                };
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error adding book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }
<span class="hljs-comment">// ...</span>
</code></pre>
<p>In this code, we are creating a new book entity from the <code>CreateBookRequest</code> object, mapping the data from the <code>CreateBookRequest</code> object to the book entity, saving the book entity to the database, and returning the book entity as a <code>BookResponse</code> object.</p>
<p>We are also logging information and errors using the <code>ILogger</code> dependency. If an exception occurs during the process, we log the error message and rethrow the exception.</p>
<p>Now that we have implemented the <code>AddBookAsync</code> method, let's implement the <code>GetBookByIdAsync</code> method.</p>
<h3 id="heading-how-to-implement-the-getbookbyidasync-method">How to Implement the <code>GetBookByIdAsync</code> Method</h3>
<p>The <code>GetBookByIdAsync</code> method is used to retrieve a book by its ID from the database. In this method, we will query the database for the book with the specified ID, map the book entity to a <code>BookResponse</code> object, and return the <code>BookResponse</code> object.</p>
<p>Update the <code>GetBookByIdAsync</code> method in the <code>BookService</code> class as follows:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Services/BookService.cs</span>

<span class="hljs-comment">//... </span>

    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get a book by its ID</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="id"&gt;</span>ID of the book<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>Details of the book<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;BookResponse&gt;  <span class="hljs-title">GetBookByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Find the book by its ID</span>
                <span class="hljs-keyword">var</span> book = <span class="hljs-keyword">await</span> _context.Books.FindAsync(id);
                <span class="hljs-keyword">if</span> (book == <span class="hljs-literal">null</span>)
                {
                    _logger.LogWarning(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> not found."</span>);
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
                }

                <span class="hljs-comment">// Return the details of the book</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = book.Id,
                    Title = book.Title,
                    Author = book.Author,
                    Description = book.Description,
                    Category = book.Category,
                    Language = book.Language,
                    TotalPages = book.TotalPages
                };
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error retrieving book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }

<span class="hljs-comment">//...</span>
</code></pre>
<p>In this code, we are querying the database for the book with the specified ID, mapping the book entity to a <code>BookResponse</code> object, and returning the <code>BookResponse</code> object. We are also logging information and errors using the <code>ILogger</code> dependency.</p>
<p>If the book with the specified ID is not found, we log a warning message and return null. If an exception occurs during the process, we log the error message and rethrow the exception.</p>
<p>Now that we have implemented the <code>GetBookByIdAsync</code> method, let's implement the <code>GetBooksAsync</code> method.</p>
<h3 id="heading-how-to-implement-the-getbooksasync-method">How to Implement the <code>GetBooksAsync</code> Method</h3>
<p>The <code>GetBooksAsync</code> method is used to retrieve all books from the database. In this method, we will query the database for all books, map each book entity to a <code>BookResponse</code> object, and return a list of <code>BookResponse</code> objects.</p>
<p>Update the <code>GetBooksAsync</code> method in the <code>BookService</code> class as follows:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Services/BookService.cs</span>

<span class="hljs-comment">//... </span>


  <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get all books</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>List of all books<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;BookResponse&gt;&gt; GetBooksAsync()
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Get all books from the database</span>
                <span class="hljs-keyword">var</span> books = <span class="hljs-keyword">await</span> _context.Books.ToListAsync();

                <span class="hljs-comment">// Return the details of all books</span>
                <span class="hljs-keyword">return</span> books.Select(book =&gt; <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = book.Id,
                    Title = book.Title,
                    Author = book.Author,
                    Description = book.Description,
                    Category = book.Category,
                    Language = book.Language,
                    TotalPages = book.TotalPages
                });
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error retrieving books: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }
<span class="hljs-comment">//...</span>
</code></pre>
<p>Here, we are querying the database for all books, mapping each book entity to an <code>BookResponse</code> object, and returning a list of <code>BookResponse</code> objects. We are also logging information and errors using the <code>ILogger</code> dependency. If an exception occurs during the process, we log the error message and rethrow the exception.</p>
<p>Now that we have implemented the <code>GetBooksAsync</code> method, let's implement the <code>UpdateBookAsync</code> method.</p>
<h3 id="heading-how-to-implement-the-updatebookasync-method">How to Implement the <code>UpdateBookAsync</code> Method</h3>
<p>The <code>UpdateBookAsync</code> method is used to update an existing book in the database. In this method, we will query the database for the book with the specified ID, update the book entity with the data from the <code>UpdateBookRequest</code> object, save the updated book entity to the database, and return the updated book entity as a <code>BookResponse</code> object.</p>
<p>Update the <code>UpdateBookAsync</code> method in the <code>BookService</code> class as follows:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/BookService.cs</span>
 <span class="hljs-comment">//...</span>
 <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Update an existing book</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="id"&gt;</span>ID of the book to be updated<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="book"&gt;</span>Updated book model<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>Details of the updated book<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;BookResponse&gt; <span class="hljs-title">UpdateBookAsync</span>(<span class="hljs-params">Guid id, UpdateBookRequest book</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Find the existing book by its ID</span>
                <span class="hljs-keyword">var</span> existingBook = <span class="hljs-keyword">await</span> _context.Books.FindAsync(id);
                <span class="hljs-keyword">if</span> (existingBook == <span class="hljs-literal">null</span>)
                {
                    _logger.LogWarning(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> not found."</span>);
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
                }

                <span class="hljs-comment">// Update the book details</span>
                existingBook.Title = book.Title;
                existingBook.Author = book.Author;
                existingBook.Description = book.Description;
                existingBook.Category = book.Category;
                existingBook.Language = book.Language;
                existingBook.TotalPages = book.TotalPages;

                <span class="hljs-comment">// Save the changes to the database</span>
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
                _logger.LogInformation(<span class="hljs-string">"Book updated successfully."</span>);

                <span class="hljs-comment">// Return the details of the updated book</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = existingBook.Id,
                    Title = existingBook.Title,
                    Author = existingBook.Author,
                    Description = existingBook.Description,
                    Category = existingBook.Category,
                    Language = existingBook.Language,
                    TotalPages = existingBook.TotalPages
                };
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error updating book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }
<span class="hljs-comment">//...</span>
</code></pre>
<p>Here, we are querying the database for the book with the specified ID, updating the book entity with the data from the <code>UpdateBookRequest</code> object, saving the updated book entity to the database, and returning the updated book entity as a <code>BookResponse</code> object. We are also logging information and errors using the <code>ILogger</code> dependency.</p>
<p>If the book with the specified ID is not found, we log a warning message and return null. If an exception occurs during the process, we log the error message and rethrow the exception.</p>
<p>Now that we have implemented the <code>UpdateBookAsync</code> method, let's implement the <code>DeleteBookAsync</code> method.</p>
<h3 id="heading-how-to-implement-the-deletebookasync-method">How to Implement the <code>DeleteBookAsync</code> Method</h3>
<p>The <code>DeleteBookAsync</code> method is used to delete an existing book from the database. In this method, we will query the database for the book with the specified ID, remove the book entity from the database, and return a boolean value indicating whether the book was successfully deleted.</p>
<p>Update the <code>DeleteBookAsync</code> method in the <code>BookService</code> class as follows:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/BookService.cs</span>

 <span class="hljs-comment">//...</span>


<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Delete a book by its ID</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="id"&gt;</span>ID of the book to be deleted<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>True if the book was deleted, false otherwise<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">DeleteBookAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Find the book by its ID</span>
                <span class="hljs-keyword">var</span> book = <span class="hljs-keyword">await</span> _context.Books.FindAsync(id);
                <span class="hljs-keyword">if</span> (book == <span class="hljs-literal">null</span>)
                {
                    _logger.LogWarning(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> not found."</span>);
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
                }

                <span class="hljs-comment">// Remove the book from the database</span>
                _context.Books.Remove(book);
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
                _logger.LogInformation(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> deleted successfully."</span>);
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error deleting book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }
<span class="hljs-comment">//...</span>
</code></pre>
<p>In this code, we are querying the database for the book with the specified ID, removing the book entity from the database, and returning a boolean value indicating whether the book was successfully deleted. We are also logging information and errors using the <code>ILogger</code> dependency.</p>
<p>If the book with the specified ID is not found, we log a warning message and return false. If an exception occurs during the process, we log the error message and rethrow the exception.</p>
<p>Now you have successfully implemented the business logic for the <code>AddBookAsync</code>, <code>GetBookByIdAsync</code>, <code>GetBooksAsync</code>, <code>UpdateBookAsync</code>, and <code>DeleteBookAsync</code> methods in the <code>BookService</code> class. These methods handle the CRUD operations for books, validate book data, and handle exceptions. By now, your <code>BookService</code> class should look like this:</p>
<pre><code class="lang-csharp">

<span class="hljs-keyword">using</span> bookapi_minimal.AppContext;
<span class="hljs-keyword">using</span> bookapi_minimal.Contracts;
<span class="hljs-keyword">using</span> bookapi_minimal.Interfaces;
<span class="hljs-keyword">using</span> bookapi_minimal.Models;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookService</span> : <span class="hljs-title">IBookService</span>
    {
          <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ApplicationContext _context; <span class="hljs-comment">// Database context</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;BookService&gt; _logger; <span class="hljs-comment">// Logger for logging information and error</span>
          <span class="hljs-comment">// Constructor to initialize the database context and logger</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BookService</span>(<span class="hljs-params">ApplicationContext context, ILogger&lt;BookService&gt; logger</span>)</span>
        {
            _context = context;
            _logger = logger;
        }

           <span class="hljs-comment"><span class="hljs-doctag">///</span> Add a new book</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="createBookRequest"&gt;</span>Book request to be added<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>Details of the created book<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;BookResponse&gt; <span class="hljs-title">AddBookAsync</span>(<span class="hljs-params">CreateBookRequest createBookRequest</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> book = <span class="hljs-keyword">new</span> BookModel
                {
                    Title = createBookRequest.Title,
                    Author = createBookRequest.Author,
                    Description = createBookRequest.Description,
                    Category = createBookRequest.Category,
                    Language = createBookRequest.Language,
                    TotalPages = createBookRequest.TotalPages
                };

                <span class="hljs-comment">// Add the book to the database</span>
                _context.Books.Add(book);
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
                _logger.LogInformation(<span class="hljs-string">"Book added successfully."</span>);

                <span class="hljs-comment">// Return the details of the created book</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = book.Id,
                    Title = book.Title,
                    Author = book.Author,
                    Description = book.Description,
                    Category = book.Category,
                    Language = book.Language,
                    TotalPages = book.TotalPages
                };
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error adding book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }

          <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get a book by its ID</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="id"&gt;</span>ID of the book<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>Details of the book<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;BookResponse&gt;  <span class="hljs-title">GetBookByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Find the book by its ID</span>
                <span class="hljs-keyword">var</span> book = <span class="hljs-keyword">await</span> _context.Books.FindAsync(id);
                <span class="hljs-keyword">if</span> (book == <span class="hljs-literal">null</span>)
                {
                    _logger.LogWarning(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> not found."</span>);
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
                }

                <span class="hljs-comment">// Return the details of the book</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = book.Id,
                    Title = book.Title,
                    Author = book.Author,
                    Description = book.Description,
                    Category = book.Category,
                    Language = book.Language,
                    TotalPages = book.TotalPages
                };
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error retrieving book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }



  <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Get all books</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>List of all books<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;BookResponse&gt;&gt; GetBooksAsync()
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Get all books from the database</span>
                <span class="hljs-keyword">var</span> books = <span class="hljs-keyword">await</span> _context.Books.ToListAsync();

                <span class="hljs-comment">// Return the details of all books</span>
                <span class="hljs-keyword">return</span> books.Select(book =&gt; <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = book.Id,
                    Title = book.Title,
                    Author = book.Author,
                    Description = book.Description,
                    Category = book.Category,
                    Language = book.Language,
                    TotalPages = book.TotalPages
                });
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error retrieving books: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }


         <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Update an existing book</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="id"&gt;</span>ID of the book to be updated<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="book"&gt;</span>Updated book model<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>Details of the updated book<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;BookResponse&gt; <span class="hljs-title">UpdateBookAsync</span>(<span class="hljs-params">Guid id, UpdateBookRequest book</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Find the existing book by its ID</span>
                <span class="hljs-keyword">var</span> existingBook = <span class="hljs-keyword">await</span> _context.Books.FindAsync(id);
                <span class="hljs-keyword">if</span> (existingBook == <span class="hljs-literal">null</span>)
                {
                    _logger.LogWarning(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> not found."</span>);
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
                }

                <span class="hljs-comment">// Update the book details</span>
                existingBook.Title = book.Title;
                existingBook.Author = book.Author;
                existingBook.Description = book.Description;
                existingBook.Category = book.Category;
                existingBook.Language = book.Language;
                existingBook.TotalPages = book.TotalPages;

                <span class="hljs-comment">// Save the changes to the database</span>
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
                _logger.LogInformation(<span class="hljs-string">"Book updated successfully."</span>);

                <span class="hljs-comment">// Return the details of the updated book</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BookResponse
                {
                    Id = existingBook.Id,
                    Title = existingBook.Title,
                    Author = existingBook.Author,
                    Description = existingBook.Description,
                    Category = existingBook.Category,
                    Language = existingBook.Language,
                    TotalPages = existingBook.TotalPages
                };
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error updating book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }



        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> Delete a book by its ID</span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;param name="id"&gt;</span>ID of the book to be deleted<span class="hljs-doctag">&lt;/param&gt;</span></span>
        <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;returns&gt;</span>True if the book was deleted, false otherwise<span class="hljs-doctag">&lt;/returns&gt;</span></span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">DeleteBookAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-comment">// Find the book by its ID</span>
                <span class="hljs-keyword">var</span> book = <span class="hljs-keyword">await</span> _context.Books.FindAsync(id);
                <span class="hljs-keyword">if</span> (book == <span class="hljs-literal">null</span>)
                {
                    _logger.LogWarning(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> not found."</span>);
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
                }

                <span class="hljs-comment">// Remove the book from the database</span>
                _context.Books.Remove(book);
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
                _logger.LogInformation(<span class="hljs-string">$"Book with ID <span class="hljs-subst">{id}</span> deleted successfully."</span>);
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(<span class="hljs-string">$"Error deleting book: <span class="hljs-subst">{ex.Message}</span>"</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }

    }
}
</code></pre>
<p>Congratulations! You have successfully implemented the business logic for the <code>AddBookAsync</code>, <code>GetBookByIdAsync</code>, <code>GetBooksAsync</code>, <code>UpdateBookAsync</code>, and <code>DeleteBookAsync</code> methods in the <code>BookService</code> class.</p>
<p>There's one thing we need to do: we need to register the service in our extension method. Let's go ahead and do that.</p>
<p>In your <code>ServiceExtensions.cs</code> file, add the following code:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Extensions/ServiceExtensions.cs</span>

<span class="hljs-comment">//..</span>

 builder.Services.AddScoped&lt;IBookService, BookService&gt;();
<span class="hljs-comment">//...</span>
</code></pre>
<p>This will register the <code>BookService</code> class as a scoped service. This means that the service will be created once per request and disposed of after the request is complete.</p>
<p>Now that we have the service working, let's go ahead and create the exception classes.</p>
<h2 id="heading-how-to-create-exceptions">How to Create Exceptions</h2>
<p>Properly handling exceptions is crucial for ensuring the stability and reliability of an application. In the context of ASP.NET Core, there are two main types of exceptions:</p>
<ul>
<li><p><strong>System Exceptions</strong>: These are exceptions thrown by the .NET runtime or the underlying system.</p>
</li>
<li><p><strong>Application Exceptions</strong>: These are exceptions thrown by the application code to handle specific errors or conditions.</p>
</li>
</ul>
<p>In ASP.NET Core with .NET 8, a new feature called global exception handling was introduced. This feature allows you to handle exceptions globally in your application, making it easier to manage errors and provide a consistent user experience.</p>
<p>In our application, we will create custom exception classes to handle specific errors and conditions. We’ll also leverage the global exception handling feature to manage exceptions globally, ensuring a uniform approach to error handling across the entire application.</p>
<p>We are going to create the following exception classes:</p>
<ul>
<li><p><code>NoBookFoundException</code>: Thrown when a book with the specified ID is not found.</p>
</li>
<li><p><code>BookDoesNotExistException</code>: Thrown when a book with the specified ID does not exist.</p>
</li>
<li><p><code>GlobalExceptionHandler</code>: Handles exceptions globally in the application.</p>
</li>
</ul>
<p>In the <code>Exceptions</code> folder, create a new file named <code>NoBookFoundException.cs</code> and add the following code:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Exceptions/NoBookFoundException.cs</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Exceptions</span>
{

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">NoBookFoundException</span> : <span class="hljs-title">Exception</span>
    {

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">NoBookFoundException</span>(<span class="hljs-params"></span>) : <span class="hljs-title">base</span>(<span class="hljs-params"><span class="hljs-string">"No books found"</span></span>)</span>
        {}
    }
}
</code></pre>
<p>In this code, we are creating a custom exception class named <code>NoBookFoundException</code> that inherits from the <code>Exception</code> class. The <code>NoBookFoundException</code> class is used to handle the scenario where no books are found in the database. We are also providing a custom error message for the exception.</p>
<p>In the <code>Exceptions</code> folder, create a new file named <code>BookDoesNotExistException.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Exceptions</span>
{
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookDoesNotExistException</span> : <span class="hljs-title">Exception</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BookDoesNotExistException</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> id</span>) : <span class="hljs-title">base</span>(<span class="hljs-params"><span class="hljs-string">$"Book with id <span class="hljs-subst">{id}</span> does not exist"</span></span>)</span>
        {
            <span class="hljs-keyword">this</span>.id = id;
        } 

    }
}
</code></pre>
<p>In this code, we are creating a custom exception class named <code>BookDoesNotExistException</code> that inherits from the <code>Exception</code> class. The <code>BookDoesNotExistException</code> class is used to handle the scenario where a book with the specified ID does not exist in the database. We are also providing a custom error message for the exception.</p>
<p>In the <code>Exceptions</code> folder, create a new file named <code>GlobalExceptionHandler.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Exceptions/GlobalExceptionHandler.cs</span>

<span class="hljs-keyword">using</span> System.Net;
<span class="hljs-keyword">using</span> bookapi_minimal.Contracts;
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Diagnostics;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Exceptions</span>
{

   <span class="hljs-comment">// Global exception handler class implementing IExceptionHandler</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">GlobalExceptionHandler</span> : <span class="hljs-title">IExceptionHandler</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;GlobalExceptionHandler&gt; _logger;

        <span class="hljs-comment">// Constructor to initialize the logger</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">GlobalExceptionHandler</span>(<span class="hljs-params">ILogger&lt;GlobalExceptionHandler&gt; logger</span>)</span>
        {
            _logger = logger;
        }

        <span class="hljs-comment">// Method to handle exceptions asynchronously</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">TryHandleAsync</span>(<span class="hljs-params">
            HttpContext httpContext,
            Exception exception,
            CancellationToken cancellationToken</span>)</span>
        {
            <span class="hljs-comment">// Log the exception details</span>
            _logger.LogError(exception, <span class="hljs-string">"An error occurred while processing your request"</span>);

            <span class="hljs-keyword">var</span> errorResponse = <span class="hljs-keyword">new</span> ErrorResponse
            {
                Message = exception.Message,
                Title = exception.GetType().Name
            };

            <span class="hljs-comment">// Determine the status code based on the type of exception</span>
            <span class="hljs-keyword">switch</span> (exception)
            {
                <span class="hljs-keyword">case</span> BadHttpRequestException:
                    errorResponse.StatusCode = (<span class="hljs-keyword">int</span>)HttpStatusCode.BadRequest;
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">case</span> NoBookFoundException:
                <span class="hljs-keyword">case</span> BookDoesNotExistException:
                    errorResponse.StatusCode = (<span class="hljs-keyword">int</span>)HttpStatusCode.NotFound;
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">default</span>:
                    errorResponse.StatusCode = (<span class="hljs-keyword">int</span>)HttpStatusCode.InternalServerError;
                    <span class="hljs-keyword">break</span>;
            }

            <span class="hljs-comment">// Set the response status code</span>
            httpContext.Response.StatusCode = errorResponse.StatusCode;

            <span class="hljs-comment">// Write the error response as JSON</span>
            <span class="hljs-keyword">await</span> httpContext.Response.WriteAsJsonAsync(errorResponse, cancellationToken);

            <span class="hljs-comment">// Return true to indicate that the exception was handled</span>
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    }
}
</code></pre>
<p>Let's break down the code above:</p>
<ul>
<li><p>We define a class named <code>GlobalExceptionHandler</code> that implements the <code>IExceptionHandler</code> interface. The <code>IExceptionHandler</code> interface is used to handle exceptions globally in the application.</p>
</li>
<li><p>The <code>GlobalExceptionHandler</code> class contains a constructor that initializes the <code>ILogger&lt;GlobalExceptionHandler&gt;</code> dependency. The <code>ILogger</code> is used for logging information and errors.</p>
</li>
<li><p>The <code>TryHandleAsync</code> method is used to handle exceptions asynchronously. This method accepts the <code>HttpContext</code>, <code>Exception</code>, and <code>CancellationToken</code> as parameters.</p>
</li>
<li><p>We log the exception details using the <code>ILogger</code> dependency.</p>
</li>
<li><p>We create an <code>ErrorResponse</code> object to represent the error response returned by the API. The <code>ErrorResponse</code> object contains the error message, title, and status code.</p>
</li>
<li><p>We determine the status code based on the type of exception. If the exception is a <code>BadHttpRequestException</code>, we set the status code to <code>BadRequest</code>. If the exception is a <code>NoBookFoundException</code> or <code>BookDoesNotExistException</code>, we set the status code to <code>NotFound</code>. Otherwise, we set the status code to <code>InternalServerError</code>.</p>
</li>
<li><p>We set the response status code using the <code>httpContext.Response.StatusCode</code> property.</p>
</li>
<li><p>We write the error response as JSON using the <code>httpContext.Response.WriteAsJsonAsync</code> method.</p>
</li>
<li><p>We return <code>true</code> to indicate that the exception was handled successfully.</p>
</li>
</ul>
<p>Now that we have created the exception classes, let's register the <code>GlobalExceptionHandler</code> in the dependency injection container. Since we created an Extension method for registering services in the dependency injection container, we will add the <code>GlobalExceptionHandler</code> to the <code>ServiceExtensions</code> class.</p>
<p>Update the <code>ServiceExtensions</code> class in the <code>Extensions</code> folder as follows:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Extensions/ServiceExtensions.cs</span>
<span class="hljs-comment">//...</span>
builder.Services.AddExceptionHandler&lt;GlobalExceptionHandler&gt;();

builder.Services.AddProblemDetails();

<span class="hljs-comment">//...</span>
</code></pre>
<p>The <code>AddExceptionHandler</code> method registers the <code>GlobalExceptionHandler</code> in the dependency injection container. The <code>AddProblemDetails</code> method registers the <code>ProblemDetails</code> class in the dependency injection container.</p>
<p>Now that we have registered the <code>GlobalExceptionHandler</code> in the dependency injection container, we can use it to handle exceptions globally in our application. In the next section, we will create the API endpoints to interact with the book data.</p>
<h2 id="heading-how-to-create-the-api-endpoints">How to Create the API Endpoints</h2>
<p>In the context of minimal APIs in ASP.NET Core, there are many ways to set up your endpoints.</p>
<p>You can define them directly in your <code>Program.cs</code> file. But as your project grows and you need to add more endpoints or functionality, it’s helpful to organize your code better. One way to achieve this is by creating a separate class to handle all the endpoints.</p>
<p>As we’ve discussed above, minimal APIs don’t use controllers or views like traditional ASP.NET Core applications. Instead, they use methods such as <code>MapGet</code>, <code>MapPost</code>, <code>MapPut</code>, and <code>MapDelete</code> to define HTTP methods and routes for API endpoints.</p>
<p>To get started, navigate to the <code>Endpoints</code> folder and create a new file named <code>BookEndpoints.cs</code>. Add the following code to the file:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Endpoints/BookEndpoints.cs</span>



<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Endpoints</span>
{
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookEndPoint</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IEndpointRouteBuilder <span class="hljs-title">MapBookEndPoint</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IEndpointRouteBuilder app</span>)</span>
        {


            <span class="hljs-keyword">return</span> app;
        }
    }
}
</code></pre>
<p>The <code>BookEndpoints</code> class contains a <code>MapBookEndPoint</code> method that returns an <code>IEndpointRouteBuilder</code> object. The <code>IEndpointRouteBuilder</code> object is used to define the HTTP methods and routes for the API endpoints. In the next sections, we will define the API endpoints for <code>creating</code>, <code>reading</code>, <code>updating</code>, and <code>deleting</code> books.</p>
<h3 id="heading-how-to-create-the-addbookasync-books-endpoint">How to Create the <code>AddBookAsync</code> Books Endpoint</h3>
<p>In this section, we will create the <code>AddBookAsync</code> endpoint. This endpoint will accept a <code>Book</code> object as a JSON payload and add it to the database. We will use the <code>MapPost</code> method to define the HTTP method and route for this endpoint.</p>
<p>Add the following code to the <code>BookEndpoints</code> class:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Endpoints/BookEndpoints.cs</span>


<span class="hljs-comment">//...</span>
   <span class="hljs-comment">// Endpoint to add a new book</span>
      app.MapPost(<span class="hljs-string">"/books"</span>, <span class="hljs-keyword">async</span> (CreateBookRequest createBookRequest, IBookService bookService) =&gt;
        {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.AddBookAsync(createBookRequest);
        <span class="hljs-keyword">return</span> Results.Created(<span class="hljs-string">$"/books/<span class="hljs-subst">{result.Id}</span>"</span>, result); 
        });


<span class="hljs-comment">//...</span>
</code></pre>
<ul>
<li><p><strong>Route Definition</strong>: The MapPost method defines the route for the endpoint as <code>/books</code>.</p>
</li>
<li><p><strong>Request Model</strong>: The endpoint accepts an <code>CreateBookRequest</code> object as a JSON payload. The <code>CreateBookRequest</code> object contains the data required to create a new book.</p>
</li>
<li><p><strong>Response Model</strong>: The endpoint returns a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data for the newly created book.</p>
</li>
<li><p><strong>Return Value</strong>: The endpoint returns a <code>Created</code> result. The <code>Created</code> result contains the location of the newly created book and the <code>Book</code> object.</p>
</li>
</ul>
<h3 id="heading-how-to-create-the-getbookasync-book-endpoint">How to Create the <code>GetBookAsync</code> Book Endpoint</h3>
<p>In this section, we will create the <code>GetBookAsync</code> endpoint. This endpoint will accept a book ID as a query parameter and return the book with the specified ID. We will use the <code>MapGet</code> method to define the HTTP method and route for this endpoint.</p>
<p>Add the following code to the <code>BookEndpoints</code> class:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Endpoints/BookEndpoints.cs</span>

<span class="hljs-comment">// ...</span>
    <span class="hljs-comment">// Endpoint to get all books</span>
    app.MapGet(<span class="hljs-string">"/books"</span>, <span class="hljs-keyword">async</span> (IBookService bookService) =&gt;
     {
    <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.GetBooksAsync();
    <span class="hljs-keyword">return</span> Results.Ok(result);
});


<span class="hljs-comment">//...</span>
</code></pre>
<ul>
<li><p><strong>Route Definition</strong>: The MapGet method defines the route for the endpoint as <code>/books</code>.</p>
</li>
<li><p><strong>Request Model</strong>: The endpoint accepts a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data required to create a new book.</p>
</li>
<li><p><strong>Response Model</strong>: The endpoint returns a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data for the newly created book.</p>
</li>
<li><p><strong>Return Value</strong>: The endpoint returns an <code>Ok</code> result. The <code>Ok</code> result contains the <code>Book</code> object.</p>
</li>
</ul>
<h3 id="heading-how-to-create-the-getbookbyidasync-book-endpoint">How to Create the <code>GetBookByIdAsync</code> Book Endpoint</h3>
<p>In this section, we will create the <code>GetBookByIdAsync</code> endpoint. This endpoint will accept a book ID as a route parameter and return the book with the specified ID. We will use the <code>MapGet</code> method to define the HTTP method and route for this endpoint.</p>
<p>Add the following code to the <code>BookEndpoints</code> class:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Endpoints/BookEndpoints.cs</span>
<span class="hljs-comment">//...</span>
<span class="hljs-comment">// Endpoint to get a book by ID</span>

  app.MapGet(<span class="hljs-string">"/books/{id:guid}"</span>, <span class="hljs-keyword">async</span> (Guid id, IBookService bookService) =&gt;
  {
    <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.GetBookByIdAsync(id);
    <span class="hljs-keyword">return</span> result != <span class="hljs-literal">null</span> ? Results.Ok(result) : Results.NotFound();
});

<span class="hljs-comment">//...</span>
</code></pre>
<ul>
<li><p><strong>Route Definition</strong>: The MapGet method defines the route for the endpoint as <code>/books/{id:guid}</code>. The <code>{id:guid}</code> parameter specifies that the <code>id</code> parameter should be a GUID.</p>
</li>
<li><p><strong>Request Model</strong>: The endpoint accepts a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data required to create a new book.</p>
</li>
<li><p><strong>Response Model</strong>: The endpoint returns a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data for the newly created book.</p>
</li>
<li><p><strong>Return Value</strong>: The endpoint returns an <code>Ok</code> result if the book is found. The <code>NotFound</code> result is returned if the book is not found.</p>
</li>
</ul>
<h3 id="heading-how-to-create-the-updatebookasync-book-endpoint">How to Create the <code>UpdateBookAsync</code> Book Endpoint</h3>
<p>In this section, we will create the <code>UpdateBookAsync</code> endpoint. This endpoint will accept a book ID as a route parameter and an <code>Book</code> object as a JSON payload and update the book with the specified ID. We will use the <code>MapPut</code> method to define the HTTP method and route for this endpoint.</p>
<p>Add the following code to the <code>BookEndpoints</code> class:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Endpoints/BookEndpoints.cs</span>

<span class="hljs-comment">//...</span>
   <span class="hljs-comment">// Endpoint to update a book by ID</span>
    app.MapPut(<span class="hljs-string">"/books/{id:guid}"</span>, <span class="hljs-keyword">async</span> (Guid id, UpdateBookRequest updateBookRequest, IBookService bookService) =&gt;
 {
<span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.UpdateBookAsync(id, updateBookRequest);
<span class="hljs-keyword">return</span> result != <span class="hljs-literal">null</span> ? Results.Ok(result) : Results.NotFound();
});

<span class="hljs-comment">//...</span>
</code></pre>
<ul>
<li><p><strong>Route Definition</strong>: The MapPut method defines the route for the endpoint as <code>/books/{id:guid}</code>. The <code>{id:guid}</code> parameter specifies that the <code>id</code> parameter should be a GUID.</p>
</li>
<li><p><strong>Request Model</strong>: The endpoint accepts a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data required to create a new book.</p>
</li>
<li><p><strong>Response Model</strong>: The endpoint returns a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data for the newly created book.</p>
</li>
<li><p><strong>Return Value</strong>: The endpoint returns an <code>Ok</code> result if the book is found. The <code>NotFound</code> result is returned if the book is not found.</p>
</li>
</ul>
<h3 id="heading-how-to-create-the-deletebookasync-book-endpoint">How to Create the <code>DeleteBookAsync</code> Book Endpoint</h3>
<p>In this section, we will create the <code>DeleteBookAsync</code> endpoint. This endpoint will accept a book ID as a route parameter and delete the book with the specified ID. We will use the <code>MapDelete</code> method to define the HTTP method and route for this endpoint.</p>
<p>Add the following code to the <code>BookEndpoints</code> class:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Endpoints/BookEndpoints.cs</span>

<span class="hljs-comment">//...</span>
   <span class="hljs-comment">// Endpoint to delete a book by ID</span>
 app.MapDelete(<span class="hljs-string">"/books/{id:guid}"</span>, <span class="hljs-keyword">async</span> (Guid id, IBookService bookService) =&gt;
{
<span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.DeleteBookAsync(id);
   <span class="hljs-keyword">return</span> result ? Results.NoContent() : Results.NotFound();
});


<span class="hljs-comment">//...</span>
</code></pre>
<ul>
<li><p><strong>Route Definition</strong>: The MapDelete method defines the route for the endpoint as <code>/books/{id:guid}</code>. The <code>{id:guid}</code> parameter specifies that the <code>id</code> parameter should be a GUID.</p>
</li>
<li><p><strong>Request Model</strong>: The endpoint accepts a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data required to create a new book.</p>
</li>
<li><p><strong>Response Model</strong>: The endpoint returns a <code>Book</code> object as a JSON payload. The <code>Book</code> object contains the data for the newly created book.</p>
</li>
<li><p><strong>Return Value</strong>: The endpoint returns a <code>NoContent</code> result if the book is deleted successfully. The <code>NotFound</code> result is returned if the book is not found.</p>
</li>
</ul>
<p>Now we have defined all the methods for the book endpoints. So your endpoint class should look like this:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Endpoints/BookEndpoints.cs</span>
<span class="hljs-keyword">using</span> bookapi_minimal.Contracts;
<span class="hljs-keyword">using</span> bookapi_minimal.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Endpoints</span>
{
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookEndPoint</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IEndpointRouteBuilder <span class="hljs-title">MapBookEndPoint</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IEndpointRouteBuilder app</span>)</span>
        {
            <span class="hljs-comment">// Define the endpoints</span>

            <span class="hljs-comment">// Endpoint to add a new book</span>
            app.MapPost(<span class="hljs-string">"/books"</span>, <span class="hljs-keyword">async</span> (CreateBookRequest createBookRequest, IBookService bookService) =&gt;
            {
                <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.AddBookAsync(createBookRequest);
                <span class="hljs-keyword">return</span> Results.Created(<span class="hljs-string">$"/books/<span class="hljs-subst">{result.Id}</span>"</span>, result); 
            });


               <span class="hljs-comment">// Endpoint to get all books</span>
            app.MapGet(<span class="hljs-string">"/books"</span>, <span class="hljs-keyword">async</span> (IBookService bookService) =&gt;
            {
                <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.GetBooksAsync();
                <span class="hljs-keyword">return</span> Results.Ok(result);
            });

            <span class="hljs-comment">// Endpoint to get a book by ID</span>
            app.MapGet(<span class="hljs-string">"/books/{id:guid}"</span>, <span class="hljs-keyword">async</span> (Guid id, IBookService bookService) =&gt;
            {
                <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.GetBookByIdAsync(id);
                <span class="hljs-keyword">return</span> result != <span class="hljs-literal">null</span> ? Results.Ok(result) : Results.NotFound();
            });


            <span class="hljs-comment">// Endpoint to update a book by ID</span>
            app.MapPut(<span class="hljs-string">"/books/{id:guid}"</span>, <span class="hljs-keyword">async</span> (Guid id, UpdateBookRequest updateBookRequest, IBookService bookService) =&gt;
            {
                <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.UpdateBookAsync(id, updateBookRequest);
                <span class="hljs-keyword">return</span> result != <span class="hljs-literal">null</span> ? Results.Ok(result) : Results.NotFound();
            });

            <span class="hljs-comment">// Endpoint to delete a book by ID</span>
            app.MapDelete(<span class="hljs-string">"/books/{id:guid}"</span>, <span class="hljs-keyword">async</span> (Guid id, IBookService bookService) =&gt;
            {
                <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> bookService.DeleteBookAsync(id);
                <span class="hljs-keyword">return</span> result ? Results.NoContent() : Results.NotFound();
            });

            <span class="hljs-keyword">return</span> app;
        }
    }
}
</code></pre>
<p>Congratulations! You have created all the endpoints for the book API. The endpoints handle the CRUD operations for books and return the appropriate responses based on the request and data.</p>
<h3 id="heading-how-to-register-the-endpoints">How to Register the Endpoints</h3>
<p>After defining the API endpoints for the book API, the next step is to register these endpoints in the <code>Program.cs</code> file. We will use the <code>MapBookEndpoints</code> method to register the book endpoints.</p>
<p>We should also clean up our <code>Program.cs</code> class to ensure it remains organized and maintainable.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

<span class="hljs-keyword">using</span> System.Reflection;
<span class="hljs-keyword">using</span> bookapi_minimal.Endpoints;
<span class="hljs-keyword">using</span> bookapi_minimal.Services;
<span class="hljs-keyword">using</span> Microsoft.OpenApi.Models;

<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);


builder.AddApplicationServices();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c=&gt;
{
    c.SwaggerDoc(<span class="hljs-string">"v1"</span>, <span class="hljs-keyword">new</span> OpenApiInfo { Title = <span class="hljs-string">"Mimal API"</span>, Version = <span class="hljs-string">"v1"</span>, Description = <span class="hljs-string">"Showing how you can build minimal "</span> +
        <span class="hljs-string">"api with .net"</span> });


    <span class="hljs-comment">// Set the comments path for the Swagger JSON and UI.</span>
    <span class="hljs-keyword">var</span> xmlFile = <span class="hljs-string">$"<span class="hljs-subst">{Assembly.GetExecutingAssembly().GetName().Name}</span>.xml"</span>;
    <span class="hljs-keyword">var</span> xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    c.IncludeXmlComments(xmlPath);

});
<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-comment">// Configure the HTTP request pipeline.</span>
<span class="hljs-keyword">if</span> (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseExceptionHandler();


app.MapGroup(<span class="hljs-string">"/api/v1/"</span>)
   .WithTags(<span class="hljs-string">" Book endpoints"</span>)
   .MapBookEndPoint();

app.Run();
</code></pre>
<p>Let's break down the key components of the <code>Program.cs</code> file:</p>
<ul>
<li><p><strong>AddApplicationServices</strong>: This method registers the necessary services for the API. It is an extension method we created earlier to add services to the dependency injection container.</p>
</li>
<li><p><strong>AddSwaggerGen</strong>: This method registers the Swagger generator, which is used to create the Swagger documentation for the API. We specify the title, version, and description of the API in the Swagger document.</p>
</li>
<li><p><strong>MapGroup</strong>: This method groups the endpoints. It takes a path as a parameter and returns an <code>IEndpointRouteBuilder</code> object. We use the <code>WithTags</code> method to add tags to the endpoints and the <code>MapBookEndpoints</code> method to register the book endpoints.</p>
</li>
<li><p><strong>Run</strong>: This method starts the application.</p>
</li>
</ul>
<p>To enable Swagger documentation, you need to add the <code>GenerateDocumentationFile</code> property to your <code>.csproj</code> file. In this example, the file is named <code>bookapi-minimal.csproj</code>, but the name may vary based on your project.</p>
<p>Add the following line to your <code>.csproj</code> file:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">GenerateDocumentationFile</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">GenerateDocumentationFile</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>
</code></pre>
<p>By the end, bookapi-minimal.csproj should look like this:</p>
<pre><code class="lang-xml">
<span class="hljs-tag">&lt;<span class="hljs-name">Project</span> <span class="hljs-attr">Sdk</span>=<span class="hljs-string">"Microsoft.NET.Sdk.Web"</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TargetFramework</span>&gt;</span>net8.0<span class="hljs-tag">&lt;/<span class="hljs-name">TargetFramework</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Nullable</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">Nullable</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ImplicitUsings</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">ImplicitUsings</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">GenerateDocumentationFile</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">GenerateDocumentationFile</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">RootNamespace</span>&gt;</span>bookapi_minimal<span class="hljs-tag">&lt;/<span class="hljs-name">RootNamespace</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">ItemGroup</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"FluentValidation.DependencyInjectionExtensions"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"11.9.2"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.AspNetCore.OpenApi"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.6"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.Design"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag">&lt;/<span class="hljs-name">IncludeAssets</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">PrivateAssets</span>&gt;</span>all<span class="hljs-tag">&lt;/<span class="hljs-name">PrivateAssets</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">PackageReference</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.SqlServer"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.Tools"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.8"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag">&lt;/<span class="hljs-name">IncludeAssets</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">PrivateAssets</span>&gt;</span>all<span class="hljs-tag">&lt;/<span class="hljs-name">PrivateAssets</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">PackageReference</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Swashbuckle.AspNetCore"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"6.4.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ItemGroup</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">Project</span>&gt;</span>
</code></pre>
<p>Now that we have registered the book endpoints in the <code>Program.cs</code> file, we can run the application and test the API endpoints using Swagger.</p>
<p>When you run the application, you should see the Swagger documentation at the following URL: <a target="_blank" href="https://localhost:5001/swagger/index.html"><code>https://localhost:5001/swagger/index.html</code></a>. The Swagger documentation provides information about the API endpoints, request and response models, and allows you to test the endpoints directly from the browser. You should see something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732624213627/e1e3b3d1-2ecb-486a-b95b-28b958f52462.png" alt="Book API Endpoints Swagger UI " width="2474" height="1242" loading="lazy"></p>
<p>Congratulations! You have implemented the business logic for the book service, created custom exceptions, defined API endpoints, and registered the endpoints in the <code>Program.cs</code> file. You have also enabled Swagger documentation to test the API endpoints.</p>
<h2 id="heading-how-to-add-seed-data-to-the-database">How to Add Seed Data to the Database</h2>
<p>One more important step is to seed the database with initial data when the application starts. This seed data will populate the database, allowing you to test your API endpoints without manually adding data.</p>
<p>Let's add some seed data before performing migrations and testing our API endpoints.</p>
<p>To achieve this, we will create a new class in our Configuration folder called <code>BookTypeConfigurations</code> and add the following code:</p>
<pre><code class="lang-csharp">

<span class="hljs-keyword">using</span> bookapi_minimal.Models;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore.Metadata.Builders;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">bookapi_minimal.Configurations</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookTypeConfigurations</span> : <span class="hljs-title">IEntityTypeConfiguration</span>&lt;<span class="hljs-title">BookModel</span>&gt;
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">EntityTypeBuilder&lt;BookModel&gt; builder</span>)</span>
        {
            <span class="hljs-comment">// Configure the table name</span>
            builder.ToTable(<span class="hljs-string">"Books"</span>);

            <span class="hljs-comment">// Configure the primary key</span>
            builder.HasKey(x =&gt; x.Id);

            <span class="hljs-comment">// Configure properties</span>
            builder.Property(x =&gt; x.Id).ValueGeneratedOnAdd();
            builder.Property(x =&gt; x.Title).IsRequired().HasMaxLength(<span class="hljs-number">100</span>);
            builder.Property(x =&gt; x.Author).IsRequired().HasMaxLength(<span class="hljs-number">100</span>);
            builder.Property(x =&gt; x.Description).IsRequired().HasMaxLength(<span class="hljs-number">500</span>);
            builder.Property(x =&gt; x.Category).IsRequired().HasMaxLength(<span class="hljs-number">100</span>);
            builder.Property(x =&gt; x.Language).IsRequired().HasMaxLength(<span class="hljs-number">50</span>);
            builder.Property(x =&gt; x.TotalPages).IsRequired();

            <span class="hljs-comment">// Seed data</span>
            builder.HasData(
                <span class="hljs-keyword">new</span> BookModel
                {
                    Id = Guid.NewGuid(),
                    Title = <span class="hljs-string">"The Alchemist"</span>,
                    Author = <span class="hljs-string">"Paulo Coelho"</span>,
                    Description = <span class="hljs-string">"The Alchemist follows the journey of an Andalusian shepherd"</span>,
                    Category = <span class="hljs-string">"Fiction"</span>,
                    Language = <span class="hljs-string">"English"</span>,
                    TotalPages = <span class="hljs-number">208</span>
                },
                <span class="hljs-keyword">new</span> BookModel
                {
                    Id = Guid.NewGuid(),
                    Title = <span class="hljs-string">"To Kill a Mockingbird"</span>,
                    Author = <span class="hljs-string">"Harper Lee"</span>,
                    Description = <span class="hljs-string">"A novel about the serious issues of rape and racial inequality."</span>,
                    Category = <span class="hljs-string">"Fiction"</span>,
                    Language = <span class="hljs-string">"English"</span>,
                    TotalPages = <span class="hljs-number">281</span>
                },
                <span class="hljs-keyword">new</span> BookModel
                {
                    Id = Guid.NewGuid(),
                    Title = <span class="hljs-string">"1984"</span>,
                    Author = <span class="hljs-string">"George Orwell"</span>,
                    Description = <span class="hljs-string">"A dystopian social science fiction novel and cautionary tale about the dangers of totalitarianism. "</span>,
                  Category = <span class="hljs-string">"Fiction"</span>,
                  Language = <span class="hljs-string">"English"</span>,
                  TotalPages = <span class="hljs-number">328</span>
                } 
            );
        }
    }
}
</code></pre>
<p>Let's break down the code above:</p>
<p>In Entity Framework Core, you can use the <code>IEntityTypeConfiguration</code> interface to configure the entity type and seed data for the database. The <code>BookTypeConfigurations</code> class implements the <code>IEntityTypeConfiguration&lt;BookModel&gt;</code> interface and provides the configuration for the <code>BookModel</code> entity.</p>
<ul>
<li><p><strong>Configure Method</strong>: This method is used to configure the <code>BookModel</code> entity type. It defines the table name, primary key, and properties for the <code>BookModel</code> entity.</p>
<ul>
<li><p><strong>Table Name</strong>: The <code>ToTable</code> method specifies the name of the table to be created in the database. In this case, the table name is set to "Books".</p>
</li>
<li><p><strong>Primary Key</strong>: The <code>HasKey</code> method specifies the primary key for the <code>BookModel</code> entity. The primary key is set to the <code>Id</code> property.</p>
</li>
<li><p><strong>Properties</strong>: The <code>Property</code> method configures the properties of the <code>BookModel</code> entity. It specifies the data type, length, and constraints for each property.</p>
</li>
</ul>
</li>
<li><p><strong>Seed Data</strong>: The <code>HasData</code> method seeds the database with initial data. It creates three <code>BookModel</code> objects with sample data for testing the API endpoints.</p>
</li>
</ul>
<p>Now that we have created the <code>BookTypeConfigurations</code> class, we need to register this configuration in the <code>ApplicationContext</code> class. This ensures that the configuration is applied when the database is created or migrated.</p>
<p>We’re finally almost ready to test our API. But before we do that, we need to perform migrations to create the database and apply the seed data.</p>
<p>Remember that we added our database connection string in the <code>appsettings.json</code> file? Now let's perform a migration and later update our database for the migration to take effect.</p>
<h2 id="heading-how-to-perform-a-migration">How to Perform a Migration</h2>
<p>Migrations allow you to update the database schema based on changes made to your model classes. In Entity Framework Core, you can use the <code>dotnet ef migrations add</code> command to create a new migration reflecting these changes.</p>
<p>To perform a migration, run the following command in the terminal:</p>
<pre><code class="lang-bash">dotnet ef migrations add InitialCreate
</code></pre>
<p>If the command is successful, you should see an output similar to this:</p>
<pre><code class="lang-bash">Build started...
Build succeeded.
Done. To undo this action, use <span class="hljs-string">'ef migrations remove'</span>
</code></pre>
<p>You will now see a new folder called <code>Migrations</code> in your project. This folder contains the migration files that were created based on the changes made to your model classes. These migration files include the SQL commands required to update the database schema.</p>
<h3 id="heading-how-to-update-the-database">How to Update the Database</h3>
<p>After creating the migration, you need to apply the migration to update the database schema. You can use the <code>dotnet ef database update</code> command to apply the migration and update the database. Make sure the SQL Server is running.</p>
<p>Run the following command in the terminal:</p>
<pre><code class="lang-bash">
dotnet ef database update
</code></pre>
<p>This will update the database schema based on the changes made to your model classes. Make sure there are no errors on your database connection string.</p>
<h2 id="heading-how-to-test-the-api-endpoints">How to Test the API Endpoints</h2>
<p>Now we can test our endpoints using Swagger. To do this, run the application by executing the following command in the terminal:</p>
<pre><code class="lang-bash">
dotnet run
</code></pre>
<p>This will run our application. You can open your browser and navigate to <a target="_blank" href="https://localhost:5001/swagger/index.html"><code>https://localhost:5001/swagger/index.html</code></a> to access the Swagger documentation. You should see a list of API endpoints, request and response models, and the ability to test the endpoints directly from the browser.</p>
<p>If your port number is different from <code>5001</code>, don't worry – it will still work. The port might change depending on the type of machine you're using, but it will still achieve the same result.</p>
<h3 id="heading-how-to-test-the-get-all-books-endpoint">How to Test the <code>Get All Books</code> Endpoint</h3>
<p>To test the <code>Get All Books</code> endpoint, follow these steps:</p>
<ol>
<li><p>In the Swagger documentation, click on the <code>GET /api/v1/books</code> endpoint.</p>
</li>
<li><p>Click the <code>Try it out</code> button.</p>
</li>
<li><p>Click the <code>Execute</code> button.</p>
</li>
</ol>
<p>This will send a request to the API to retrieve all the books in the database.</p>
<p>You should see the response from the API, which will include the list of books that were seeded in the database.</p>
<p>The image below shows the response from the API:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732624950148/b497bc8e-727a-43c9-910f-755b3b6f208b.png" alt="Get All Books Endpoint Swagger UI " width="2391" height="1277" loading="lazy"></p>
<h3 id="heading-how-to-test-the-get-book-by-id-endpoint">How to Test the <code>Get Book by ID</code> Endpoint</h3>
<p>To test the <code>Get Book by ID</code> endpoint, follow these steps:</p>
<ol>
<li><p>In the Swagger documentation, click on the <code>GET /api/v1/books/{id}</code> endpoint.</p>
</li>
<li><p>Enter the ID of a book in the <code>id</code> field. You can use one of the book IDs that was seeded in the database.</p>
</li>
<li><p>Click the <code>Try it out</code> button.</p>
</li>
</ol>
<p>This will send a request to the API to retrieve the book with the specified ID. You should see the response from the API, which will include the book with the specified ID.</p>
<p>The image below shows the response from the API:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732625042363/fe356453-afa6-4a78-b963-d0befff7bd63.png" alt="Get Book By ID Endpoint Swagger UI " width="2342" height="1282" loading="lazy"></p>
<h3 id="heading-how-to-test-the-add-book-endpoint">How to Test the <code>Add Book</code> Endpoint</h3>
<p>To test the <code>Add Book</code> endpoint, follow these steps:</p>
<ol>
<li><p>In the Swagger documentation, click on the <code>POST /api/v1/books</code> endpoint.</p>
</li>
<li><p>Click the <code>Try it out</code> button.</p>
</li>
<li><p>Enter the book details in the request body.</p>
</li>
<li><p>Click the <code>Execute</code> button.</p>
</li>
</ol>
<p>This will send a request to the API to add a new book to the database.</p>
<p>You should see the response from the API, which will include the newly created book.</p>
<p>The image below shows the response from the API:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732625138350/faa54e57-e560-49ac-976a-b074e8eebb13.png" alt="Add Book Endpoint Swagger UI " width="2322" height="1292" loading="lazy"></p>
<h3 id="heading-how-to-test-the-update-book-endpoint">How to Test the <code>Update Book</code> Endpoint</h3>
<p>To test the <code>Update Book</code> endpoint, follow these steps:</p>
<ol>
<li><p>In the Swagger documentation, click on the <code>PUT /api/v1/books/{id}</code> endpoint.</p>
</li>
<li><p>Enter the ID of a book in the <code>id</code> field. You can use the id of one of the books that we just added.</p>
</li>
<li><p>Click the <code>Try it out</code> button.</p>
</li>
</ol>
<p>This will send a request to the API to update the book with the specified ID.</p>
<p>You should see the response from the API, which will include the updated book.</p>
<p>The image below shows the response from the API:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732625300781/3de90d6c-92ca-40cb-a54e-2236ec921d86.png" alt="Update Book Endpoint Swagger UI " width="2326" height="1311" loading="lazy"></p>
<h3 id="heading-how-to-test-the-delete-book-endpoint">How to Test the <code>Delete Book</code> Endpoint</h3>
<p>To test the <code>Delete Book</code> endpoint, follow these steps:</p>
<ol>
<li><p>In the Swagger documentation, click on the <code>DELETE /api/v1/books/{id}</code> endpoint.</p>
</li>
<li><p>Enter the ID of a book in the <code>id</code> field. You can use any of the ids from the books that we just added or the seeded data.</p>
</li>
<li><p>Click the <code>Try it out</code> button.</p>
</li>
</ol>
<p>This will send a request to the API to delete the book with the specified ID.</p>
<p>The image below shows the response from the API:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732625225432/3b066f4c-2bf2-4f0c-a104-a94dbbad1706.png" alt="Delete Book Endpoint Swagger UI " width="2327" height="1270" loading="lazy"></p>
<p>Congratulations! You have implemented all the CRUD operations for books and tested the API endpoints using Swagger, verifying that they work as expected. You can now build on this foundation to add more features and functionality to your API.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This handbook explored how to create a minimal API in ASP.NET Core with .NET 8. We built a comprehensive book API that supports CRUD operations, implemented custom exceptions, defined and registered API endpoints, and enabled Swagger documentation for easy testing.</p>
<p>Following this tutorial, you have gained a solid foundation for building minimal APIs with ASP.NET Core. You can now apply this knowledge and create robust APIs for various domains and industries.</p>
<p>I hope you found this tutorial both helpful and informative. Thank you for reading!</p>
<p>Feel free to connect with me on social media:</p>
<ul>
<li><p><a target="_blank" href="https://x.com/Clifftech_Dev">Twitter</a></p>
</li>
<li><p><a target="_blank" href="https://www.linkedin.com/in/isaiah-clifford-opoku/">LinkedIn</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/Clifftech123">GitHub</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
