← tutti gli articoli

.NET

Cosa ho imparato sulla costruzione di REST API in .NET

Una API CRUD semplice, niente pagamenti, niente di sofisticato. HTTP verb, routing, EF Core, e status code stanno finalmente facendo click mentre la costruisco.

Cosa ho imparato sulla costruzione di REST API in .NET

Ho appena finito la mia prima vera REST API in .NET: un'app CRUD semplice, niente pagamenti, niente di sofisticato. È basilare, ma costruirla è dove molti dei fondamentali stanno finalmente facendo click per me.

Far corrispondere gli HTTP verb a quello che dovrebbero fare

Sapevo che GET, POST, PUT, e DELETE esistevano prima di iniziare questo, ma non capivo davvero perché contasse quale usavi finché non ho costruito qualcosa con tutti e quattro. GET legge, POST crea, PUT aggiorna, DELETE rimuove, e ognuno si mappa in modo pulito su un'action del Controller. Vedendoli fianco a fianco, smette di essere una regola astratta e diventa ovvio.

Routing e Controller

Sto usando i Controller perché è quello che usa ogni tutorial che ho seguito. [ApiController], [Route("api/products")], e un'action per HTTP verb:

[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
    private readonly AppDbContext _context;

    public ProductsController(AppDbContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async Task<IActionResult> GetAll()
    {
        var products = await _context.Products.ToListAsync();
        return Ok(products);
    }
}

All'inizio sembravano tanti attribute da memorizzare, ma una volta capito che la route e il verb insieme decidono quale action gira, smette di sembrare arbitrario.

Parlare con il database tramite EF Core

Questa è la prima volta che uso Entity Framework Core per qualcosa di reale invece dell'esempio giocattolo di un tutorial. Un model, un DbContext, e una connection string:

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

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<Product> Products => Set<Product>();
}

Poi eseguendo la migration per creare davvero la tabella:

dotnet ef migrations add InitialCreate
dotnet ef database update

Quella è stata la prima volta che l'API sembrava fare qualcosa invece di restituire solo dati finti.

Gli status code significano davvero qualcosa

Prima di questo avrei restituito 200 per praticamente tutto. Costruire questa API è la prima volta che presto attenzione a quale sto davvero rimandando indietro:

[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
    var product = await _context.Products.FindAsync(id);

    if (product is null)
    {
        return NotFound();
    }

    return Ok(product);
}

[HttpPost]
public async Task<IActionResult> Create(Product product)
{
    _context.Products.Add(product);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}

NotFound() dà un 404, Ok() un 200, e CreatedAtAction restituisce un 201 insieme all'URL della cosa appena creata. Farli bene rende l'API comprensibile a chiunque la chiami senza dover leggere il codice.

Dove questo mi lascia

Niente in questo progetto è avanzato. È una semplice API CRUD con un database dietro, e la maggior parte di quello che ho imparato è solo i fondamentali che scattano al loro posto per la prima volta. È tutto quello che è per adesso, ed è abbastanza per dove sono.