Neste post daremos continuidade a uma série de postagens sobre Web-Services divididos entre conceitos teóricos e praticos. Nos 3 primeiros posts focou-se em teoria com um sobre Web Services, outro sobre RESTful Web Services e mais um sobre os HTTP Status Codes mais comuns. Este post por sua vez complementa a parte teórica e o que foi desenvolvido na série de posts em que implementamos API’s REST com SpringBoot. Faremos aqui uma abordagem das mesmas situações só que dessa vez com a tecnologia ASP.NET Core. Além disso o código desse projeto se baseia no post anterior Criando um endpoint REST com ASP.NET Core. Então antes de começar confira o post Criando uma simples Web API RESTful em .NET Core 2.0.



Agora faremos algumas alterações no projeto original. Para começar crie os seguintes source folders Models, Services e dentro de Services Implementations. A estrutura da nossa arquitetura deve ficar similar a imagem abaixo.



Arquitetura da Aplicação



Feito isto crie uma classe chamada Person, no source folder Models, com as informações que serão representadas pelo nosso endpoint REST.

namespace SimpleRestfulAPIWithAspNetCore.Models
{
    public class Person
    {
        public long Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
    }
}


Feito isto crie uma interface com o nome IPersonService no source folder Services.


using SimpleRestfulAPIWithAspNetCore.Models;
using System.Collections.Generic;

namespace SimpleRestfulAPIWithAspNetCore.Services
{
    public interface IPersonService
    {
        Person Create(Person person);
        Person FindById(string personId);
        List<Person> FindAll();
        Person Update(Person person);
        void Delete(string personId);
    }
}



Agora vamos criar a implementação para a interface PersonService. No source folder Services –> Implementations crie a classe PersonServiceImpl que implementa a interface que acabamos de criar.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SimpleRestfulAPIWithAspNetCore.Models;
using System.Threading;

namespace SimpleRestfulAPIWithAspNetCore.Services.Implementations
{
    public class PersonServiceImpl : IPersonService
    {
        // Contador responsável por gerar um fake ID já que não estamos
        // acessando nenhum banco de dados
        private volatile int count;

        // Metodo responsável por criar uma nova pessoa
        // Se tivéssemos um banco de dados esse seria o
        // momento de persistir os dados
        public Person Create(Person person)
        {
            return person;
        }

        // Método responsável por retornar uma pessoa
        // como não acessamos nenhuma base de dados
        // estamos retornando um mock
        public Person FindById(string personId)
        {
            return new Person
            {
                Id = IncrementAndGet(),
                FirstName = "Leandro",
                LastName = "Costa",
                Address = "Uberlândia - Minas Gerais - Brasil"
            };
        }

        // Método responsável por retornar todas as pessoas
        // mais uma vez essas informações são mocks
        public List<Person> FindAll()
        {
            List<Person> persons = new List<Person>();
            for (int i = 0; i < 8; i++)
            {
                Person person = MockPerson(i);
                persons.Add(person);
            }
            return persons;
        }

        // Método responsável por atualizar uma pessoa
        // por ser mock retornamos a mesma informação passada
        public Person Update(Person person)
        {
            return person;
        }

        // Método responsável por deletar
        // uma pessoa a partir de um ID
        public void Delete(string personId)
        {
            //A nossa lógica de exclusão viria aqui
        }

        // Método responsável por mockar uma pessoa
        private Person MockPerson(int i)
        {
            return new Person
            {
                Id = IncrementAndGet(),
                FirstName = "Person Name " + i,
                LastName = "Last Name " + i,
                Address = "Some Address in Brasil " + i
            };
        }
        
        public Int32 IncrementAndGet()
        {
            return Interlocked.Increment(ref count);
        }
    }
}



Por fim renomeie a classe ValuesController para PersonController, após as alterações esse será o controller responsável por expor o endpoint de pessoas, no source folder Controllers.

using Microsoft.AspNetCore.Mvc;
using SimpleRestfulAPIWithAspNetCore.Models;
using SimpleRestfulAPIWithAspNetCore.Services;

namespace SimpleRestfulAPIWithAspNetCore.Controllers
{
    /* Mapeia as requisições de http://localhost:{porta}/api/person/
    Por padrão o ASP.NET Core mapeia todas as classes que extendem Controller
    pegando a primeira parte do nome da classe em lower case [Person]Controller
    e expõe como endpoint REST
    */
    [Route("api/[controller]")]
    public class PersonController : Controller
    {
        //Declaração do serviço usado
        private IPersonService _personService;

        /* Injeção de uma instancia de IPersonService ao criar
        uma instancia de PersonController */
        public PersonController(IPersonService personService)
        {
            _personService = personService;
        }

        //Mapeia as requisições GET para http://localhost:{porta}/api/person/
        //Get sem parâmetros para o FindAll --> Busca Todos
        [HttpGet]
        public IActionResult Get()
        {
            return Ok(_personService.FindAll());
        }

        //Mapeia as requisições GET para http://localhost:{porta}/api/person/{id}
        //recebendo um ID como no Path da requisição
        //Get com parâmetros para o FindById --> Busca Por ID
        [HttpGet("{id}")]
        public IActionResult Get(string id)
        {
            var person = _personService.FindById(id);
            if (person == null) return NotFound();
            return Ok(person);
        }

        //Mapeia as requisições POST para http://localhost:{porta}/api/person/
        //O [FromBody] consome o Objeto JSON enviado no corpo da requisição
        [HttpPost]
        public IActionResult Post([FromBody]Person person)
        {
            if (person == null) return BadRequest();
            return new ObjectResult(_personService.Create(person));
        }

        //Mapeia as requisições PUT para http://localhost:{porta}/api/person/
        //O [FromBody] consome o Objeto JSON enviado no corpo da requisição
        [HttpPut]
        public IActionResult Put([FromBody]Person person)
        {
            if (person == null) return BadRequest();
            return new ObjectResult(_personService.Update(person));
        }

        //Mapeia as requisições DELETE para http://localhost:{porta}/api/person/{id}
        //recebendo um ID como no Path da requisição
        [HttpDelete("{id}")]
        public IActionResult Delete(string id)
        {
            _personService.Delete(id);
            return NoContent();
        }
    }
}



Agora que terminamos nossa codificação inicie a aplicação. Para testar nosso endpoint e cada uma de suas operações usaremos o plugin do Chrome Postman.


Primeiro faremos uma requisição do tipo GET chamando a operação findAll para o recurso http://localhost:{porta}/api/person/. Como se pode ver na imagem abaixo obtemos como resposta um JSON com um array de pessoas.



Requisição REST do tipo GET



Agora faremos uma requisição do tipo GET chamando a operação http://localhost:{porta}/api/person/1 passando como variável path o ID da pessoa que desejamos recuperar. Da mesma forma que na requisição anterior recebemos como resposta um JSON com 1 objeto pessoa.



Requisição REST do tipo GET passando variavel via PATH

Agora faremos uma requisição do tipo POST (esse é o verbo REST usado para persistir informações) chamando a operação http://localhost:{porta}/api/person/ passando como parâmetro um JSON com um objeto pessoa no corpo da requisição. Para isso no Postman precisamos setar o tipo de requisição como POST, na aba Body definimos o JSON que representa o objeto pessoa a ser gravado, selecionamos a opção raw, definimos a opção JSON(application/json) e por fim executamos a request através do botão send.



Requisição REST do tipo POST gravando um recurso


Agora faremos uma requisição do tipo PUT (esse é o verbo REST usado para atualizar informações) chamando a operação http://localhost:{porta}/api/person/ passando como parâmetro um JSON com um objeto pessoa no corpo da requisição. Lembrando que essa representação de pessoa deve ter um ID que será usado pra localizar e atualizar um recurso na base. Para isso no Postman precisamos setar informações similares ao post a unica diferença é que o tipo de requisição deve ser o PUT.



Requisição REST do tipo PUT atualizando um recurso



Por fim faremos uma requisição do tipo DELETE (verbo REST usado excluir informações) chamando a operação http://localhost:{porta}/api/person/1 passando como variável path o ID da pessoa que desejamos remover da base. Esse tipo de requisição retorna como resposta um body vazio e um StatusCode 200 caso a operação seja executada com sucesso os StatusCode 204 (no content), 401 (Unauthorized), 403 (forbiden), 404 (not found) ou 500 (internal server error) podem ser retornados.



Requisição REST do tipo DELETE removendo um recurso



Dessa forma abordamos os 4 verbos principais do HTTP usados em aplicações REST. Continue ligado no blog, por que no próximo post iremos documentar a nossa API com o framewrok Swagger. E claro a abordagem nesses posts também será totalmente mão na massa. É isso aí bons estudos.