API Rest para almacenar imagen en base de datos con Entity Framework

Controladores API ⚙

ProfilePicture

En Visual Studio crea un nuevo controlador API con acciones de lectura y escritura, el nombre que estaré utilizando es ProfilePicturesController.cs.

El paso anterior creará una nueva clase llamada ProfilePicturesController con métodos base que usaremos como plantilla.

[Route("api/[controller]")]
[ApiController]
public class ProfilePicturesController : ControllerBase
{
    // GET: api/<ProfilePicturesController>
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/<ProfilePicturesController>/5
    [HttpGet("{id}")]
    public string Get(int id)
    {
        return "value";
    }

    // POST api/<ProfilePicturesController>
    [HttpPost]
    public void Post([FromBody] string value)
    {
    }

    // PUT api/<ProfilePicturesController>/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody] string value)
    {
    }

    // DELETE api/<ProfilePicturesController>/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
}

Para crear el constructor puedes utilizar el snippet ctor, en donde posteriormente debes agregar dos parámetros. El primer parámetro corresponde a uso de Automapper y el segundo para el contexto de la base de datos.

[Route("api/[controller]")]
[ApiController]
public class ProfilePicturesController : ControllerBase
{
    private readonly IMapper mapper;
    private readonly PictureToSQLDbContext dbContext;

    public ProfilePicturesController(IMapper mapper, PictureToSQLDbContext dbContext)
    {
        this.mapper = mapper;
        this.dbContext = dbContext;
    }
    
    // Código adicional de la clase
}

Para satisfacer las dependencias del código anterior agrega las siguientes referencias.

using AutoMapper;
using Microsoft.AspNetCore.Mvc;

GET

En el método GET podrás apreciar que la conversión con Automapper se realiza de forma transparente, en donde convertimos cada item de la lista que obtuvimos de la base de datos al tipo ProfilePictureResult que estamos utilizando como un DTO.

// GET: api/<ProfilePicturesController>
[HttpGet]
public async Task<ActionResult<IEnumerable<Dtos.ProfilePictureResult>>> Get()
{
    var results = await dbContext.ProfilePictures.Select(c => mapper.Map<Dtos.ProfilePictureResult>(c)).ToListAsync();

    return Ok(results);
}

// GET api/<ProfilePicturesController>/5
[HttpGet("{id}")]
public async Task<ActionResult<Dtos.ProfilePictureResult>> Get(int id)
{
    var profilePicture = await dbContext.ProfilePictures.FirstOrDefaultAsync(c => c.Id == id);

    if (profilePicture is null)
        return NotFound(id);

    var result = mapper.Map<Dtos.ProfilePictureResult>(profilePicture);

    return Ok(result);
}

POST

El método POST debe procesar dos conversiones, esto es debido a que se recibe la imagen como una cadena base64 la cual debe ser convertida a un arreglo de bytes. Posteriormente para la respuesta, se retorna un DTO con data adicional y la imagen nuevamente en cadena base64.

// POST api/<ProfilePi cturesController>
[HttpPost]
public async Task<ActionResult<Dtos.ProfilePictureResult>> Post(Dtos.ProfilePictureEntry profilePictureEntry)
{
    var profilePicture = mapper.Map<Models.ProfilePicture>(profilePictureEntry);

    dbContext.ProfilePictures.Add(profilePicture);

    await dbContext.SaveChangesAsync();

    return CreatedAtAction(nameof(Get), new { id = profilePicture.Id }, mapper.Map<Dtos.ProfilePictureResult>(profilePicture));
}

PUT

El método PUT lo simplificaré a únicamente la actualización, en donde se estarán reemplazando todos los campos, por lo que el mapeo se realizará sobre el objeto que obtuvimos de la consulta a la base de datos.

// PUT api/<ProfilePicturesController>/5
[HttpPut("{id}")]
public async Task<ActionResult<Dtos.ProfilePictureEntry>> Put(Dtos.ProfilePictureEntry profilePictureEntry)
{
    var profilePicture = await dbContext.ProfilePictures.FirstOrDefaultAsync(c => c.Id == id);

    if (profilePicture is null)
        return NotFound(profilePicture);

    mapper.Map<Dtos.ProfilePictureEntry, Models.ProfilePicture>(profilePictureEntry, profilePicture);

    await dbContext.SaveChangesAsync();

    var result = mapper.Map<Dtos.ProfilePictureResult>(profilePicture);

    return Ok(result);
}

DELETE

El método Delete no tendrá conversión, ya que utilizaremos el Id directamente y de ser exitosa la búsqueda, se procederá a eliminar el registro. La respuesta no devolverá contenido.

// DELETE api/<ProfilePicturesController>/5
[HttpDelete("{id}")]
public async Task<ActionResult> Delete(int id)
{
    var profilePicture = await dbContext.ProfilePictures.FirstOrDefaultAsync(c => c.Id == id);

    if (profilePicture is null)
        return NotFound(id);

    dbContext.Remove(profilePicture);

    await dbContext.SaveChangesAsync();

    return NoContent();
}

Al compilar el proyecto y ejecutarlo en modo debug se mostrará la siguiente página de Swagger en donde podremos probar el API.


1 comentario

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.