REST API Fundamentals
Build professional REST APIs on Plesk Windows hosting with ASP.NET Core.
Project Setup
dotnet new webapi -n MyApi -f net8.0
cd MyApi
Basic Controller Structure
[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
/// <summary>
/// Gets all products
/// </summary>
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<ProductDto>), 200)]
public async Task<ActionResult<IEnumerable<ProductDto>>> GetAll()
{
var products = await _productService.GetAllAsync();
return Ok(products);
}
/// <summary>
/// Gets a product by ID
/// </summary>
[HttpGet("{id}")]
[ProducesResponseType(typeof(ProductDto), 200)]
[ProducesResponseType(404)]
public async Task<ActionResult<ProductDto>> GetById(int id)
{
var product = await _productService.GetByIdAsync(id);
if (product == null)
return NotFound();
return Ok(product);
}
/// <summary>
/// Creates a new product
/// </summary>
[HttpPost]
[ProducesResponseType(typeof(ProductDto), 201)]
[ProducesResponseType(400)]
public async Task<ActionResult<ProductDto>> Create([FromBody] CreateProductDto dto)
{
var product = await _productService.CreateAsync(dto);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
/// <summary>
/// Updates an existing product
/// </summary>
[HttpPut("{id}")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public async Task<IActionResult> Update(int id, [FromBody] UpdateProductDto dto)
{
var exists = await _productService.ExistsAsync(id);
if (!exists)
return NotFound();
await _productService.UpdateAsync(id, dto);
return NoContent();
}
/// <summary>
/// Deletes a product
/// </summary>
[HttpDelete("{id}")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public async Task<IActionResult> Delete(int id)
{
var exists = await _productService.ExistsAsync(id);
if (!exists)
return NotFound();
await _productService.DeleteAsync(id);
return NoContent();
}
}
API Versioning
// Install: dotnet add package Asp.Versioning.Mvc
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
})
.AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
});
// Controller
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
public class ProductsController : ControllerBase { }
[ApiVersion("2.0")]
public class ProductsV2Controller : ControllerBase { }
Error Handling
// Global exception handler
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
var response = new
{
error = "An error occurred",
detail = app.Environment.IsDevelopment() ? error.Error.Message : null
};
await context.Response.WriteAsJsonAsync(response);
}
});
});
OpenAPI/Swagger Documentation
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "My API",
Version = "v1",
Description = "API for my application"
});
// Include XML comments
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
// Enable in production too (optional)
app.UseSwagger();
app.UseSwaggerUI();
Rate Limiting (.NET 7+)
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("fixed", opt =>
{
opt.Window = TimeSpan.FromMinutes(1);
opt.PermitLimit = 100;
});
});
app.UseRateLimiter();
// Apply to endpoint
[EnableRateLimiting("fixed")]
public async Task<IActionResult> GetAll() { }
Deployment Considerations
- Enable CORS for client applications
- Use HTTPS only in production
- Implement authentication (JWT, API Keys)
- Set up proper logging
- Configure rate limiting