Introducción a los servicios HTTP
El protocolo HTTP ha evolucionado drásticamente, dejando de ser exclusivo para la renderización de páginas web para convertirse en la columna vertebral de las APIs modernas. Su naturaleza simple, flexible y ubicua permite que prácticamente cualquier dispositivo o plataforma se conecte a estos servicios. ASP.NET Web API ofrece un marco de trabajo robusto dentro del ecosistema .NET para construir estas interfaces de programación. A continuación, desarrollaremos una API que expone un catálogo de inventario, el cual será consumido posteriormente por un cliente web ligero.
Configuración del entorno y proyecto
Para comenazr, abrimos Visual Studio y creamos un nuevo proyecto. En el panel de plantillas, navegamos hacia Visual C# y seleccionamos Web. Elegimos la plantilla ASP.NET Web Application y nombramos nuestra solución como InventoryService.
En el diálogo de configuración, es fundamental seleccionar la plantilla Empty y marcar únicamente la casilla de verificación para Web API. Esta configuración evita la inclusión de dependencias innecesarias de ASP.NET MVC, manteniendo el proyecto enfocado exclusivamente en la exposición de la API.
Definición del modelo de dominio
Un modelo representa los datos con los que trabaja nuestra aplicación. ASP.NET Web API se encarga de serializar automáticamente estos objetos a formatos como JSON o XML, escribiéndolos en el cuerpo de la respuesta HTTP. El cliente decidirá el formato de salida mediante el encabezado Accept en su petición.
En el explorador de soluciones, creamos una nueva clase dentro de la carpeta Models llamada CatalogItem con la siguiente estructura:
namespace InventoryService.Models
{
public class CatalogItem
{
public int ItemId { get; set; }
public string Title { get; set; }
public string Department { get; set; }
public decimal Cost { get; set; }
}
}
Implementación del controlador API
Los controladores son los encargados de procesar las peticiones HTTP entrantes. A diferencia de los controladores MVC que heredan de Controller, los de Web API deben heredar de ApiController.
Añadimos un nuevo controlador en la carpeta Controllers, seleccionando la opción Web API Controller - Empty y lo nombramos CatalogController. Reemplazamos su contenido con la siguiente lógica, que incluye un arreglo estático para simular una base de datos:
using InventoryService.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace InventoryService.Controllers
{
public class CatalogController : ApiController
{
private readonly CatalogItem[] _inventory = new CatalogItem[]
{
new CatalogItem { ItemId = 101, Title = "Mechanical Keyboard", Department = "Electronics", Cost = 89.99M },
new CatalogItem { ItemId = 102, Title = "Ergonomic Mouse", Department = "Electronics", Cost = 45.50M },
new CatalogItem { ItemId = 103, Title = "Standing Desk", Department = "Furniture", Cost = 299.00M }
};
public IEnumerable<CatalogItem> FetchAllItems()
{
return _inventory;
}
public IHttpActionResult FetchItemById(int id)
{
var item = _inventory.FirstOrDefault(i => i.ItemId == id);
if (item == null)
{
return NotFound();
}
return Ok(item);
}
}
}
El enrutamiento predeterminado de Web API mapeará estos métodos a los siguientes endpoints: api/catalog para obtener la lista completa y api/catalog/101 para obtener un artículo específico por su identificador.
Consumo de la API desde el frontend
Para probar la API, creamos un archivo HTML estático llamado dashboard.html en la raíz del proyecto. Utilizaremos jQuery para realizar peticiones AJAX y actualizar el DOM dinámicamente.
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Panel de Inventario</title>
</head>
<body>
<section>
<h2>Catálogo Completo</h2>
<ul id="itemList"></ul>
</section>
<section>
<h2>Búsqueda por Identificador</h2>
<input type="number" id="searchInput" placeholder="ID" />
<button onclick="searchItem()">Buscar</button>
<p id="searchResult"></p>
</section>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
const apiEndpoint = 'api/catalog';
$(document).ready(function () {
$.getJSON(apiEndpoint)
.done(function (items) {
$.each(items, function (index, item) {
$('#itemList').append(
$('<li>').text(`${item.Title} - $${item.Cost}`)
);
});
});
});
function searchItem() {
const targetId = $('#searchInput').val();
$.getJSON(`${apiEndpoint}/${targetId}`)
.done(function (data) {
$('#searchResult').text(`Encontrado: ${data.Title} ($${data.Cost})`);
})
.fail(function (xhr, status, error) {
$('#searchResult').text(`Error: ${error}`);
});
}
</script>
</body>
</html>
Al cargar el documento, la función $.getJSON realiza una petición GET a api/catalog. La promesa .done() itera sobre el array de objetos JSON devuelto e inyecta cada elemento en la lista HTML. De manera similar, la función searchItem() concatena el identificador proporcionado por el usuario a la URL base para recuperar y mostrar los detalles de un único recurso.