Anexsoft | Blog y dictado de cursos de Tecnología

En este encontrarás tutoriales de tecnología como PHP, ASP.NET MVC, Front-End, entre otros y cursos exigentes de modalidad online que te ayudarán a crecer profesionalmente.

Queremos mejorar la calidad de nuestros cursos. Por favor ayúdanos llenando esta pequeña encuesta
Tips para construir una RESTFul Api Rest con Net Core 2.0
Actualizado el 27 Abril, 2018 y leído 3,977 veces
Calificación: 10.00 / 10

Tips para construir una RESTFul Api Rest con Net Core 2.0

Anexsoft

En esta nueva entrada voy a compartir una serie de consejos en base a mi experiencia para elaborar mejores APIs siguiendo una serie de recomendaciones y buenas prácticas usando C# y el framework Net Core 2.0.

 

Usa los verbos HTTP en vez decorar tus rutas con verbos

Es muy común y si, yo también lo he hecho que el nombre de nuestros endpoints (rutas, recursos http) los nombres contengan verbos. Pues esto esta mal, no es una buena práctica.

  • users/getLastUsers
  • users/getById
  • users/createOrUpdate

Lo correcto sería usar sustantivos y como buena recomendación deben ir en plural. En este caso piensen el módulo que van a trabajar.

  • [GET] users
  • [GET] users/1
  • [POST] users
  • [PUT] users
  • [DELETE] users/1

Veamos un ejemplo práctico de como debería quedar nuestro código implementando los verbos HTTP:

[Route("v1/users")]
public class UserController : Controller
{
    private readonly IUserService _userService;

    public UserController(IUserService userService)
    {
        _userService = userService;
    }

    // Route: users/{id}/studies
    [HttpGet("{id}/studies")]
    public async Task<IActionResult> UserStudiers()
    {
        return Ok(
            await _userService.GetAll()
        );
    }

    // Route: users/{id}
    [HttpGet("{id}", Name = "GetReviewById")]
    public async Task<IActionResult> Get(int id)
    {
        var result = await _userService.Get(id);

        if (result == null)
            return NotFound();

        return Ok(
            await _userService.Get(id)
        );
    }

    // Route: users
    [HttpPost]
    public async Task<IActionResult> Create([FromBody] UserPostDto model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var newRecord = await _userService.Create(model);

        if (newRecord == null)
            throw new Exception("Record can't be created");

        return CreatedAtRoute(
            "GetReviewById",
            new { id = newRecord.Id },
            newRecord
        );
    }

    // Route: users/{id}
    [HttpPut("{id}")]
    public async Task<IActionResult> Update(int id, [FromBody] UserPutDto model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        await _userService.Update(id, model);

        return NoContent();
    }

    // Route: users/{id}
    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        await _userService.Delete(id);

        return NoContent();
    }
}

El cliente o persona que use nuestra API deberá especificar el verbo HTTP para acceder a nuestros endpoints.

 

Acerca de los verbos HTTP

 

GET

  • Usa este verbo para obtener un registro o colección
  • Lo común es tener 2 endpoints uno para listar una colección completa y otro para listar un solo registro
  • En el caso de listar colecciones lo correcto es usar filtros para mantener un estandard (esto lo veremos más adelante)
  • Puedes navegar por las propiedades de tu recurso usando GET. Imagínate que quiero traer los estudios de un determinado usuario
[HttpGet("{id}/studies")]
public async Task<IActionResult> UserStudiers()
{
    return Ok(
        await _userService.GetAll()
    );
}

Como se especifica primero deberá estar presenta el ID del usuario a consultar y luego sus estudios haciendo referencia a su propiedad.

  • El código de respuesta deberá ser 200 (Ok)
  • Responde 404 cuando el registro no haya sido encontrado.
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
    var result = await _userService.Get(id);

    if (result == null)
        return NotFound();

    return Ok(
        await _userService.Get(id)
    );
}

 

POST

  • Este verbo es usado para crear un nuevo elemento dentro de nuestro curso
  • Tipos de respuesta esperado:
    • Created 201: se genero un nuevo recurso y se adjunta la ruta de este en la cabecera
    • Accepted 202: la petición ha sido aceptada pero aún no ha terminado, normalmente para procesos que se ejecutarán en segundo plano
[HttpPost]
public async Task<IActionResult> Create([FromBody] UserPostDto model)
{
    var newRecord = await _userService.Create(model);

    return CreatedAtRoute(
        "GetReviewById",
        new { id = newRecord.Id },
        newRecord
    );
}

En este ejemplo la propiedad CreatedAtRoute recibe como parámetros la ruta para obtener el nuevo registro el cual será respondido en la cabecera de nuestra petición HTTP y; adicionalmente, estoy pasando el nuevo registro.

 

PUT

  • Comunmente es usado para modificar un registro actual pero en si también se puede usar para crear un registro. En sí lo que hace es que sino existe el recurso especificado lo intentará crear.
  • Tipos de respuesta esperado:
    • Created 204: el recurso actual ha sido modificado
    • Accepted 202: la petición ha sido aceptada pero aún no ha terminado, normalmente para procesos que se ejecutarán en segundo plano
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, [FromBody] UserPutDto model)
{
    await _userService.Update(id, model);

    return NoContent();
}

 

DELETE

  • Lo usamos para eliminar un registro
  • Puede responder 3 estados según sea el caso, todo los códigos 200 son respuestas satisfactorias
  • Tipos de respuesta esperado:
    • No Content (204): el recurso actual ha sido modificado en este caso produciendo su eliminación
    • Accepted (202): es usado cuando por ejemplo queremos hacer un delete masivo y este ha sido aceptado pero todavía no ejecutado
    • Ok (200): que la acción fue realizada con éxito respondiendo información adicional
// Route: users/{id}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
    await _userService.Delete(id);

    return NoContent();
}

 

Versiona tus endpoints

Es muy buena práctica versionarlos porque en un futuro quizas hagamos un cambió drástico y a nuestros clientes que usan los endpoints no deberían verse afectados, por lo menos no por un tiempo hasta que se decida migrar complemtamente la versión.

Simplemente pongamos un prefijo a nuestro controlador haciendo referencia a la versión:

[Route("v1/users")]
public class UserController : Controller
{
    ...

 

Intenta validar todo, estandarizar tus respuestas

Intenta validar los parámetros de entrada y estandarizar los mensajes para que nuestro cliente no tenga un problema al momento de deserializar el mensaje. Un ejemplo sencillo y el tipo de respuesta que daríamos sería BadRequest (400).

[HttpPost]
public async Task<IActionResult> Create([FromBody] UserPostDto model)
{
    var newRecord = await _userService.Create(model);

    return CreatedAtRoute(
        "GetReviewById",
        new { id = newRecord.Id },
        newRecord
    );
}

En otras lecciones veremos FluentValidation que es una librería excelente para validación.

En el caso de error de código o que el registro no haya podido ser creado lancemos una excepción que responderá a nuestro cliente con un status code 500.

[HttpPost]
public async Task<IActionResult> Create([FromBody] UserPostDto model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var newRecord = await _userService.Create(model);

    if (newRecord == null)
        throw new Exception("Record can't be created");

    return CreatedAtRoute(
        $"users/{newRecord.Id}",
        newRecord
    );
}

 

Documenta

Documenta todo lo que puedas, la opción más víable y práctica es mediante Swagger el cual ya veremos más adelante.

 

Conclusiones

No te rompas la cabeza y esto me paso a mí, que intentaba dar un htpp status code para cada respuesta. Lo mejor es usar los más importantes como: 200, 201, 302, 404, 400, 500 y así nos evitamos hacer sufrir a nuestro cliente.

¡Adquiera ya!

  • Código de fuente de Red Social desarrollada en ASP.NET MVC

    Código de fuente de Red Social desarrollada en ASP.NET MVC
  • Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#

    Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#
  • Software de Venta e Inventario hecho en PHP y Codeigniter

    Software de Venta e Inventario hecho en PHP y Codeigniter

Últimas publicaciones

Encuesta

¿Sobre qué te gustaría que se hable más?

Síguenos

Estudia con nosotros y crece profesionalmente

Nuestros cursos han sido hecho en base a lo que demanda el mercado hoy en día.
La experiencia obtenida es la de un ambiente laboral.

Anexsoft
© 2018 Anexsoft, blog y cursos online de TI.