Resumen

Crear controladores API en .NET es sencillo cuando entiendes la estructura: inyección de dependencias, rutas claras y buenas prácticas REST con códigos de estado correctos. Aquí verás cómo implementar GET y POST para usuarios y tareas, cómo usar CreatedAtAction y cómo probar todo con Swagger y una base de datos en memoria.

¿Cómo arrancar el controlador API con inyección de dependencias?

Antes de exponer endpoints, se inyecta el servicio en el controlador para aislar la lógica de acceso a datos. Así, el controlador orquesta y el servicio habla con el AppDbContext.

¿Cómo inyectar el servicio en el constructor?

  • Recibe la interfaz del servicio en el constructor.
  • Asigna a un campo privado con guion bajo como convención.
  • Mantén el controlador delgado y sin lógica de datos.
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    private readonly IUserService _userService;

    public UserController(IUserService userService)
    {
        _userService = userService; // inyección de dependencias
    }

    // endpoints aquí...
}

¿Qué rol cumple AppDbContext y el servicio?

  • AppDbContext: persiste usuarios y tareas.
  • Servicio: intermediario entre controlador y AppDbContext.
  • Controlador: expone endpoints para ser consumidos por otras aplicaciones.

¿Qué endpoints GET y POST necesitas y cuál es su ruta?

Las rutas siguen la convención: api/nombre-del-controlador. Para usuarios: api/user. La diferencia entre obtener y crear no es la ruta, sino el verbo: GET para leer, POST para crear.

¿Cómo implementar get all y get by id?

  • GET api/user: devuelve la lista de usuarios con await al método asíncrono del servicio.
  • GET api/user/{id}: recibe un id y devuelve 404 con NotFound() si no existe.
[HttpGet]
public async Task<ActionResult> GetAll()
{
    var users = await _userService.GetAllAsync();
    return Ok(users); // 200 OK
}

[HttpGet("{id:int}")]
public async Task<ActionResult> GetById(int id)
{
    var user = await _userService.GetByIdAsync(id);
    if (user is null) return NotFound(); // 404 Not Found
    return Ok(user); // 200 OK
}
  • Buenas prácticas: usa nombres en plural cuando retornas colecciones (users).
  • Rutas: api/user y api/user/{id} con restricción de tipo int.

¿Cómo devolver created con CreatedAtAction?

Para crear, usa POST y retorna 201 con CreatedAtAction, apuntando al método que lee por id. Así confirmas que el elemento existe y devuelves la ubicación lógica.

[HttpPost]
public async Task<ActionResult> Create([FromBody] User user)
{
    var created = await _userService.CreateAsync(user);
    return CreatedAtAction(
        nameof(GetById),         // acción de lectura
        new { id = created.Id }, // ruta con id
        created                  // cuerpo completo
    ); // 201 Created
}
  • Razón: CreatedAtAction cumple el patrón REST para creación.
  • Detalle importante: pasar el nombre del método con nameof evita errores al renombrar.

¿Cómo probar con Swagger y una base de datos en memoria?

Con Swagger, puedes ejecutar GET y POST fácilmente. Al usar una base en memoria, debes proporcionar manualmente el Id en los POST, porque no hay generación automática.

¿Cómo probar con Swagger y datos en memoria?

  • Crea un usuario con POST a api/user: retorna 201 Created y el objeto creado.
  • Ejecuta GET api/user: verás la lista con el usuario recién creado.
  • Crea una tarea con POST a api/task: usa un userId existente, define id de la tarea, título y estado (por ejemplo, completa = false).
  • Ejecuta GET api/task: devuelve la colección de tareas.

Notas prácticas: - Si la documentación de Swagger muestra un esquema incorrecto para la tarea, envía solo el userId válido y los campos de la tarea. - Asegúrate de registrar controladores: services.AddControllers() y app.MapControllers(). Ambos son necesarios para que los endpoints estén activos.

¿Qué queda pendiente para completar el CRUD?

  • Implementar actualizar: método PUT o PATCH según el caso.
  • Implementar eliminar: método DELETE por id.
  • Mantener consistencia de códigos: 200/204 para actualización exitosa, 404 cuando no exista el recurso.

Habilidades y conceptos aplicados: - Inyección de dependencias para servicios en controladores. - Asincronía con Task y await para IO no bloqueante. - Buenas prácticas REST con Ok, NotFound y CreatedAtAction. - Diseño de rutas: api/user y api/user/{id:int}. - Pruebas con Swagger y base de datos en memoria.

¿Te quedaste con dudas o quieres compartir cómo implementaste update y delete? Deja tu comentario y cuéntanos qué retos encontraste.