.NET ProgrammingUnit 914 min read

Web APIs: REST, JSON, HTTP, CRUD, and ASP.NET Core Integration

Unit 9 of .NET Programming covers Web APIs—how to design, build, and consume RESTful APIs in ASP.NET Core, including HTTP methods, JSON serialization, routing, and integration with frontend apps or mobile services.

TAKEAWAYS:

  • Web APIs enable stateless communication between clients (e.g., mobile apps) and servers using HTTP/HTTPS, adhering to REST principles.
  • HTTP methods (GET, POST, PUT, DELETE) map directly to CRUD operations, and JSON is the standard data format for API responses.
  • ASP.NET Core simplifies API development with built-in controllers, dependency injection, and middleware for routing and validation.
  • Real-world APIs (e.g., eSewa’s payment verification, Khalti’s transaction endpoints) rely on secure, scalable API design to handle concurrent requests.
  • Swagger/OpenAPI tools auto-generate API documentation, while Postman is used to test endpoints interactively.
  • Security best practices (e.g., JWT tokens, HTTPS, input validation) are critical to protect APIs from attacks like SQL injection or data leaks.

What is a Web API?

A Web API (Application Programming Interface) is a contract between a client (e.g., a mobile app, web frontend, or another service) and a server. It defines:

  • What data can be requested/retrieved (e.g., user profiles, product lists).
  • How to request it (using HTTP methods like GET, POST).
  • What format the data will be in (typically JSON or XML).

Unlike traditional web pages (served via ASP.NET MVC), APIs return data, not HTML. Clients (e.g., React apps, Android apps) fetch this data and render it dynamically.

Key Characteristics of Web APIs

mindmap
  root((Web API))
    RESTful
      Stateless
      Resource-based (e.g., `/users`, `/orders`)
      HTTP Methods (GET, POST, PUT, DELETE)
    Protocols
      HTTP/HTTPS
      JSON/XML
    Design Principles
      Uniform Interface
      Client-Server Separation
      Statelessness
      Cacheability

HTTP Methods and CRUD Operations

APIs use HTTP methods to perform CRUD (Create, Read, Update, Delete) operations on resources. Below is a mapping table:

HTTP Method CRUD Operation Example Endpoint Request Body (if any) Response
GET Read /api/products/1 None { "id": 1, "name": "Laptop" }
POST Create /api/products { "name": "Phone", "price": 500 } { "id": 2, "message": "Created" }
PUT Update (full) /api/products/1 { "name": "Updated Laptop" } { "id": 1, "message": "Updated" }
PATCH Update (partial) /api/products/1 { "price": 600 } { "id": 1, "message": "Updated" }
DELETE Delete /api/products/1 None { "message": "Deleted" }

Example: eSewa’s Payment API

When you pay a bill via the eSewa app, it sends a POST request to eSewa’s API with:

  • Your user ID and transaction details (amount, bill ID).
  • The API processes the payment and returns a JSON response confirming success/failure.
{
  "status": "success",
  "transactionId": "TXN12345",
  "amount": 500,
  "message": "Payment processed"
}

Why REST?

  • Stateless: Each request from the app contains all needed data (no server-side session storage).
  • Scalable: eSewa’s servers can handle millions of concurrent POST requests.
  • Interoperable: Any app (web, mobile) can integrate with eSewa’s API using HTTP.

Building a Web API in ASP.NET Core

ASP.NET Core provides a minimal API template or controller-based approach. Below, we’ll create a simple Product API using controllers.

Step 1: Create a Controller

A controller is a class that handles HTTP requests for a specific resource (e.g., ProductsController for /api/products).

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    // In-memory "database" for demo
    private static List<Product> _products = new List<Product>
    {
        new Product { Id = 1, Name = "Laptop", Price = 1000 },
        new Product { Id = 2, Name = "Phone", Price = 500 }
    };

    // GET: api/products
    [HttpGet]
    public ActionResult<IEnumerable<Product>> Get()
    {
        return Ok(_products);
    }

    // GET: api/products/1
    [HttpGet("{id}")]
    public ActionResult<Product> Get(int id)
    {
        var product = _products.Find(p => p.Id == id);
        if (product == null) return NotFound();
        return Ok(product);
    }

    // POST: api/products
    [HttpPost]
    public ActionResult<Product> Post([FromBody] Product product)
    {
        _products.Add(product);
        return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Step 2: Test the API with Postman

  1. Install Postman (or use Swagger UI in ASP.NET Core).
  2. Send a GET request to http://localhost:5000/api/products: ![Postman GET Request](IMAGE: "postman get request example" | "Postman showing a successful GET /api/products response with JSON data")
  3. Send a POST request to create a new product:
    • Set Headers: Content-Type: application/json
    • Set Body (raw JSON):
      {
        "name": "Tablet",
        "price": 300
      }
      
    • Expected response:
      {
        "id": 3,
        "name": "Tablet",
        "price": 300
      }
      

Step 3: Enable Swagger for Documentation

Add these lines to Program.cs to auto-generate API docs:

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

app.UseSwagger();
app.UseSwaggerUI();

Now, visit http://localhost:5000/swagger to see interactive API docs:



JSON Serialization in .NET

APIs use JSON to exchange data. ASP.NET Core automatically serializes C# objects to JSON and vice versa.

Example: Serializing a Product Object

var product = new Product { Id = 1, Name = "Laptop", Price = 1000 };
string json = JsonSerializer.Serialize(product);
// Output: {"Id":1,"Name":"Laptop","Price":1000}

Customizing JSON with Attributes

Use [JsonPropertyName] to control property names in JSON:

public class Product
{
    [JsonPropertyName("product_id")]
    public int Id { get; set; }
    public string Name { get; set; }
}

Now, serialization outputs:

{ "product_id": 1, "Name": "Laptop" }

Routing in ASP.NET Core APIs

Routing determines how HTTP requests map to controller actions. Common attributes:

  • [Route("api/[controller]")]: Base route (e.g., /api/products).
  • [HttpGet], [HttpPost]: Method-specific routes.
  • [Route("api/products/{id}")]: Custom route for a specific ID.

Example: Custom Route for a Product

[HttpGet("details/{id}")]
public ActionResult<Product> GetProductDetails(int id)
{
    var product = _products.Find(p => p.Id == id);
    return Ok(product);
}

Now, GET /api/products/details/1 returns the product with ID 1.


Consuming APIs in Clients (e.g., React, Mobile Apps)

Clients use HTTP clients (e.g., HttpClient in C#, fetch in JavaScript) to call APIs.

Example: Fetching Products in a React App

async function fetchProducts() {
  const response = await fetch('http://localhost:5000/api/products');
  const products = await response.json();
  console.log(products);
  // Render products in UI
}

Example: Pathao’s Rider API Integration

Pathao’s mobile app calls its backend API to:

  1. GET /api/rides: Fetch available rides for the user.
  2. POST /api/rides: Create a new ride request with passenger details.
  3. PUT /api/rides/{id}/status: Update ride status (e.g., "Accepted", "In Progress").
sequenceDiagram
    participant User as Pathao App (User)
    participant API as Pathao API Server
    participant DB as Database

    User->>API: POST /api/rides (ride request)
    API->>DB: Save ride to DB
    API-->>User: 201 Created (ride ID)
    User->>API: GET /api/rides/{id} (poll for status)
    API->>DB: Fetch ride status
    API-->>User: 200 OK (status: "Driver assigned")

Security Best Practices for APIs

APIs are prime targets for attacks (e.g., SQL injection, DDoS, unauthorized access). Key protections:

Threat Solution ASP.NET Core Implementation
Unauthorized access JWT (JSON Web Tokens) Microsoft.AspNetCore.Authentication.JwtBearer
SQL injection Parameterized queries Use Dapper or Entity Framework Core
Data leaks Input validation [FromBody] + ModelState.IsValid
DDoS attacks Rate limiting AspNetCoreRateLimit package
Man-in-the-middle attacks HTTPS (TLS) Force HTTPS in Program.cs

Example: JWT Authentication

  1. Install NuGet package:
    dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
    
  2. Configure in Program.cs:
    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidIssuer = "your-issuer",
                ValidAudience = "your-audience",
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-secret-key"))
            };
        });
    
  3. Protect a controller:
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    [Route("api/[controller]")]
    public class SecureProductsController : ControllerBase { ... }
    

Real-World Example: Daraz’s Order API

Daraz’s e-commerce platform relies on Web APIs for:

  1. Inventory Management:
    • GET /api/products?category=electronics (fetch products).
    • POST /api/orders (create an order).
  2. Payment Processing:
    • POST /api/payments (initiate Khalti/Esewa payment).
    • GET /api/orders/{id}/status (check order status).
  3. User Accounts:
    • PUT /api/users/{id} (update profile).
    • DELETE /api/orders/{id} (cancel order).

API Workflow for a Daraz Order

flowchart TD
    A["User adds items to cart"] --> B["POST /api/cart"]
    B --> C["API validates stock"]
    C -->|"Success"| D["POST /api/orders"]
    D --> E["Payment Gateway Redirect"]
    E -->|"Payment Success"| F["PUT /api/orders/{id}/status=shipped"]
    F --> G["Notify user via email/SMS"]

Exam Tip

What to Expect in TU Exams

  1. Short Questions (2-5 marks):

    • Define REST, JSON, or JWT.
    • Differentiate between GET/POST/PUT.
    • Write a JSON snippet for a given C# object.
  2. Programming Questions (10-15 marks):

    • Build a simple API (e.g., StudentsController with GET/POST).
    • Consume an API (e.g., fetch data from a mock API using HttpClient).
    • Debug routing issues (e.g., why [HttpGet] isn’t working).
  3. Scenario-Based (5-10 marks):

    • Design an API for Nepal Stock Exchange (NEPSE) to fetch stock prices.
    • Secure an API for Khalti’s transaction endpoint using JWT.

Common Pitfalls to Avoid

  • Forgetting [ApiController]: Causes missing model validation.
  • Not using [FromBody]: Leads to 400 Bad Request for POST/PUT.
  • Hardcoding routes: Use [Route] attributes for flexibility.
  • Ignoring CORS: Always configure CorsPolicy for frontend apps.

Model Answer Snippet (Exam Style)

Question: Write a C# controller for a Books API with:

  • GET /api/books (return all books).
  • POST /api/books (add a new book).

Answer:

[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
    private static List<Book> _books = new List<Book>
    {
        new Book { Id = 1, Title = "Clean Code", Author = "Robert Martin" }
    };

    [HttpGet]
    public ActionResult<IEnumerable<Book>> Get()
    {
        return Ok(_books);
    }

    [HttpPost]
    public ActionResult<Book> Post([FromBody] Book book)
    {
        _books.Add(book);
        return CreatedAtAction(nameof(Get), new { id = book.Id }, book);
    }
}

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
}

In the Real World

  1. eSewa’s Payment API:

    • Idea Used: RESTful POST endpoint for processing transactions.
    • How: When you pay a bill, the eSewa app sends a POST request to https://api.esewa.com.np/v3.0/payment with your user ID, amount, and bill reference. The API returns a JSON response with a transaction ID or error.
    • Security: Uses JWT tokens for authentication and HTTPS to encrypt data.
  2. Khalti’s Merchant API:

    • Idea Used: Webhook + JSON responses for real-time payment updates.
    • How: Daraz integrates Khalti’s API to:
      • Initiate payments: POST /pg/v2.0/create-payment.
      • Receive webhooks: POST /webhook (triggered when payment is successful/failed).
    • Example Workflow:
      sequenceDiagram
          participant User as Daraz User
          participant Daraz as Daraz Frontend
          participant KhaltiAPI as Khalti API
          participant DarazDB as Daraz Database
      
          User->>Daraz: Clicks "Pay with Khalti"
          Daraz->>KhaltiAPI: POST /pg/v2.0/create-payment (amount=500, order_id=123)
          KhaltiAPI-->>Daraz: 200 OK (payment_url)
          Daraz->>User: Redirect to Khalti
          User->>KhaltiAPI: Completes payment
          KhaltiAPI->>Daraz: POST /webhook (payment_success)
          Daraz->>DarazDB: Update order status to "Paid"
  3. NTC’s Service Request API:

    • Idea Used: CRUD operations for managing service requests.
    • How: Citizens submit electricity/gas connection requests via the NTC website, which calls:
      • POST /api/requests (create a new request).
      • GET /api/requests/{id} (check status).
    • Real Scenario: If you file a complaint for a power outage in Kathmandu, the NTC portal sends a POST request to their backend API, which logs the issue and assigns it to a technician. You can later GET /api/requests/456 to see updates.
  4. NEPSE’s Stock Data API:

    • Idea Used: Real-time data streaming via WebSockets (or polling with GET).
    • How: Trading apps like Nepal Investment Bank’s app fetch stock prices via:
      • GET /api/stocks?symbol=NEPSE (polling every 5 seconds).
      • WebSocket: For live updates (e.g., ws://api.nepse.com/stocks).
    • Example Response:
      {
        "symbol": "NEPSE",
        "price": 2500.50,
        "change": 12.30,
        "timestamp": "2024-05-20T14:30:00"
      }
      

Based on the TU BITM syllabus for .NET Programming (IT275), unit 9.

Discussion

Loading…