.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
CacheabilityHTTP 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
POSTrequests. - 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
- Install Postman (or use Swagger UI in ASP.NET Core).
- Send a
GETrequest tohttp://localhost:5000/api/products:  - Send a
POSTrequest 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 }
- Set Headers:
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:
GET /api/rides: Fetch available rides for the user.POST /api/rides: Create a new ride request with passenger details.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
- Install NuGet package:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer - 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")) }; }); - 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:
- Inventory Management:
GET /api/products?category=electronics(fetch products).POST /api/orders(create an order).
- Payment Processing:
POST /api/payments(initiate Khalti/Esewa payment).GET /api/orders/{id}/status(check order status).
- 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
Short Questions (2-5 marks):
- Define REST, JSON, or JWT.
- Differentiate between
GET/POST/PUT. - Write a JSON snippet for a given C# object.
Programming Questions (10-15 marks):
- Build a simple API (e.g.,
StudentsControllerwithGET/POST). - Consume an API (e.g., fetch data from a mock API using
HttpClient). - Debug routing issues (e.g., why
[HttpGet]isn’t working).
- Build a simple API (e.g.,
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 to400 Bad RequestforPOST/PUT. - Hardcoding routes: Use
[Route]attributes for flexibility. - Ignoring CORS: Always configure
CorsPolicyfor 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
eSewa’s Payment API:
- Idea Used: RESTful POST endpoint for processing transactions.
- How: When you pay a bill, the eSewa app sends a
POSTrequest tohttps://api.esewa.com.np/v3.0/paymentwith 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.
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).
- Initiate payments:
- 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"
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
POSTrequest to their backend API, which logs the issue and assigns it to a technician. You can laterGET /api/requests/456to see updates.
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…