HTTP Methods
π― What You'll Learn
- Common HTTP methods (GET, POST, PUT, DELETE, PATCH)
- When to use each method
- Idempotency and safety
- RESTful API conventions
- ASP.NET Core attributes for methods
- Complete InvenTrack CRUD examples
HTTP Methods Overview
| Method | Purpose | Safe | Idempotent |
|---|---|---|---|
| GET | Retrieve data | β | β |
| POST | Create new resource | β | β |
| PUT | Update/replace resource | β | β |
| PATCH | Partial update | β | β |
| DELETE | Delete resource | β | β |
| HEAD | Get headers only | β | β |
| OPTIONS | Get allowed methods | β | β |
Safe: Doesn't modify server state (read-only)
Idempotent: Multiple identical requests have the same effect as one
1. GET - Retrieve Data
GET retrieves data without modifying server state.
Characteristics
- β Safe (read-only)
- β Idempotent (same result every time)
- β No request body
- β Can be cached
- β Can be bookmarked
// Get all products
[HttpGet]
public async Task<IActionResult> GetProducts()
{
var products = await _productService.GetAllAsync();
return Ok(products);
}
// Get single product
[HttpGet("{id}")]
public async Task<IActionResult> GetProduct(int id)
{
var product = await _productService.GetByIdAsync(id);
if (product == null)
return NotFound();
return Ok(product);
}
// Get with query parameters
[HttpGet("search")]
public async Task<IActionResult> SearchProducts(
[FromQuery] string name,
[FromQuery] decimal? minPrice,
[FromQuery] decimal? maxPrice)
{
var products = await _productService.SearchAsync(name, minPrice, maxPrice);
return Ok(products);
}
GET /api/products/123 HTTP/1.1
Host: inventrackapp.com
2. POST - Create Resource
POST creates a new resource on the server.
Characteristics
- β Not safe (modifies state)
- β Not idempotent (creates new resource each time)
- β Has request body
- Returns
201 CreatedwithLocationheader
[HttpPost]
public async Task<IActionResult> CreateProduct([FromBody] CreateProductDto dto)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var product = await _productService.CreateAsync(dto);
// Return 201 Created with Location header
return CreatedAtAction(
nameof(GetProduct),
new { id = product.Id },
product);
}
POST /api/products HTTP/1.1
Host: inventrackapp.com
Content-Type: application/json
{
"name": "Laptop",
"price": 999.99,
"quantityInStock": 50
}
HTTP/1.1 201 Created
Location: /api/products/123
Content-Type: application/json
{
"id": 123,
"name": "Laptop",
"price": 999.99,
"quantityInStock": 50
}
3. PUT - Update/Replace Resource
PUT replaces an entire resource.
Characteristics
- β Not safe (modifies state)
- β Idempotent (same result every time)
- β Has request body
- Replaces entire resource
- Returns
204 No Contentor200 OK
[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(
int id,
[FromBody] UpdateProductDto dto)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var success = await _productService.UpdateAsync(id, dto);
if (!success)
return NotFound();
return NoContent(); // 204
}
PUT /api/products/123 HTTP/1.1
Host: inventrackapp.com
Content-Type: application/json
{
"name": "Laptop Pro",
"price": 1299.99,
"quantityInStock": 30
}
4. PATCH - Partial Update
PATCH updates only specific fields of a resource.
Characteristics
- β Not safe (modifies state)
- β Not idempotent (depends on implementation)
- β Has request body
- Updates specific fields only
[HttpPatch("{id}/stock")]
public async Task<IActionResult> UpdateStock(
int id,
[FromBody] UpdateStockDto dto)
{
var success = await _productService.UpdateStockAsync(id, dto.QuantityInStock);
if (!success)
return NotFound();
return NoContent();
}
PATCH /api/products/123/stock HTTP/1.1
Host: inventrackapp.com
Content-Type: application/json
{
"quantityInStock": 75
}
PUT: Replace entire resource (all fields required)
PATCH: Update specific fields (only changed fields sent)
5. DELETE - Remove Resource
DELETE removes a resource from the server.
Characteristics
- β Not safe (modifies state)
- β Idempotent (deleting twice = same result)
- β No request body
- Returns
204 No Contentor200 OK
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
var success = await _productService.DeleteAsync(id);
if (!success)
return NotFound();
return NoContent(); // 204
}
DELETE /api/products/123 HTTP/1.1
Host: inventrackapp.com
RESTful API Conventions
| Operation | Method | URL | Success Code |
|---|---|---|---|
| List all | GET | /api/products | 200 OK |
| Get one | GET | /api/products/123 | 200 OK |
| Create | POST | /api/products | 201 Created |
| Update (full) | PUT | /api/products/123 | 204 No Content |
| Update (partial) | PATCH | /api/products/123 | 204 No Content |
| Delete | DELETE | /api/products/123 | 204 No Content |
Complete InvenTrack CRUD Example
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
// GET: api/products
[HttpGet]
public async Task<ActionResult<IEnumerable<ProductDto>>> GetProducts()
{
var products = await _productService.GetAllAsync();
return Ok(products);
}
// GET: api/products/123
[HttpGet("{id}")]
public async Task<ActionResult<ProductDto>> GetProduct(int id)
{
var product = await _productService.GetByIdAsync(id);
if (product == null)
return NotFound();
return Ok(product);
}
// POST: api/products
[HttpPost]
public async Task<ActionResult<ProductDto>> CreateProduct(
[FromBody] CreateProductDto dto)
{
var product = await _productService.CreateAsync(dto);
return CreatedAtAction(
nameof(GetProduct),
new { id = product.Id },
product);
}
// PUT: api/products/123
[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(
int id,
[FromBody] UpdateProductDto dto)
{
var success = await _productService.UpdateAsync(id, dto);
if (!success)
return NotFound();
return NoContent();
}
// PATCH: api/products/123/stock
[HttpPatch("{id}/stock")]
public async Task<IActionResult> UpdateStock(
int id,
[FromBody] UpdateStockDto dto)
{
var success = await _productService.UpdateStockAsync(id, dto.QuantityInStock);
if (!success)
return NotFound();
return NoContent();
}
// DELETE: api/products/123
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
var success = await _productService.DeleteAsync(id);
if (!success)
return NotFound();
return NoContent();
}
}
Key Takeaways
- GET: Retrieve data (safe, idempotent)
- POST: Create new resource (not safe, not idempotent)
- PUT: Replace entire resource (not safe, idempotent)
- PATCH: Partial update (not safe, not idempotent)
- DELETE: Remove resource (not safe, idempotent)
- Safe: Read-only operations (GET, HEAD, OPTIONS)
- Idempotent: Same result when called multiple times (GET, PUT, DELETE)
- Use
[HttpGet],[HttpPost], etc. attributes - Follow RESTful conventions for consistency
- Return appropriate status codes (200, 201, 204, 404)
You now understand HTTP methods! In the next section, we'll explore Status Codesβwhat they mean, when to use them, and how to return the right status code for every situation.