ASP.NET MVC - Criando uma Web API com suporte a operações CRUD
Baseado no artigo: http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web-api-that-supports-crud-operations
Se você não conhece nada sobre o recurso Web API da ASP .NET MVC 4 sugiro que leia os seguintes artigos :
Neste artigo eu vou mostrar como dar apoio a operações CRUD (Create, Reate, Update e Delete) em um serviço de HTTP usando a ASP.NET Web API.
A palavra CRUD é um acrônimo que significa "Create,Read, Udpate e Delete", que são as quatro operações básicas de um banco de dados. Muitos serviços HTTP também modelam operações CRUD através de REST ou REST-like APIs.
Neste artigo , você vai construir uma Web API muito simples para gerenciar uma lista de produtos. Cada produto conterá um nome, preço e categoria (como "papelaria" ou "informática"), além de uma identificação do produto.
A nossa API produtos irá expor os seguintes métodos:
Ação | Método HTTP | URI relativa |
Obter uma lista de produtos | GET | /api/produtos |
Obter um produto pelo seu ID | GET | /api/produtos/id |
Obter os produtos pela sua categoria | GET | /api/produtos/?categoria=categoria |
Criar um novo produto | POST | /api/produtos |
Atualizar um produto | PUT | /api/produtos/id |
Deletar um produto | DELETE | /api/produtos/id |
Observe que algumas das URIs incluem a identificação do produto no caminho. Por exemplo, para obter o produto cuja identificação é de 28, o cliente envia uma solicitação GET para http://hostname/api/produtos/28.
Os quatro principais métodos HTTP (GET, PUT, POST e DELETE) podem ser mapeados para operações CRUD como segue:
Eu vou utilizar o Visual Web Developer 2010 Express Edition ou Visual Studio 2010.(Você tem que instalar o recurso ASP .NET MVC4)
Criando uma nova Web API
Abra então o Visual Web Developer 2010 Express Edition e no menu File clique em New Project;
A seguir selecione a linguagem Visual Basic e clique em Web a selecione o template ASP .NET MVC 4 Web Application informando o nome ProdutosRepositorio e clicando no botão OK;
Na janela de diálogo New ASP.NET MVC 4 Project selecione o template Web API , o view Engine Razor , e clique no botão OK;
Será criado um projeto com uma estrutura já pronta e contendo alguns recursos definidos.
Definindo o Model
Vamos definir um Model em nosso projeto.
Um model ou Modelo é um objeto que representa os dados do nosso aplicativo. A ASP.NET Web API pode serializar automaticamente o seu modelo para JSON, XML, ou outro formato, e depois gravar os dados serializados no corpo da mensagem de resposta HTTP. Enquanto um cliente pode ler o formato de serialização, e pode também desserializar o objeto. Além disso, muitos clientes podem analisar o XML ou o JSON e também podem indicar qual o formato desejam tratar, definindo o cabeçalho Accept na mensagem de solicitação HTTP.
Clique com o botão direito sobre a pasta Models e selecione a opção Add e a seguir Class;
A seguir informe o nome da classe como Produto.vb e clique no botão Add e digite o código abaixo neste arquivo:
Public
Class
Produto Public Property Id As Integer Public Property Nome As String Public Property Categoria As String Public Property Preco As Decimal End Class |
Incluindo um repositório
Precisamos armazenar uma coleção de produtos. É uma boa ideia separar a coleção da nossa implementação do serviço. Dessa forma, podemos alterar o armazenamento de backup sem reescrever a classe de serviço. Este tipo de projeto é chamado padrão de repositório. Vamos iniciar definindo uma interface genérica para o repositório.
Clique com o botão direito sobre a pasta Models e selecione a opção Add e a seguir New Item;
Na janela Add New Item selecione o template Interface e informe o nome IProdutoRepositorio.vb e clique no botão Add;
A seguir digite o código abaixo para implementar a interface :
Public Interface IProdutoRepositorio Function GetTodos() As IEnumerable(Of Produto) Function GetPorID(id As Integer) As Produto Function Adicionar(item As Produto) As Produto Sub Remover(id As Integer) Function Atualizar(item As Produto) As Boolean End Interface |
O próximo passo será incluir uma classe chamada ProdutoRepositorio que implementar a interface que acabamos de criar.
Clique com o botão direito sobre a pasta Models e selecione a opção Add e a seguir Class;
A seguir informe o nome da classe como Produto.vb e clique no botão Add e digite o código abaixo neste arquivo:
Public Class ProdutoRepositorio Implements IProdutoRepositorio
Private produtos As New List(Of Produto)()
Public Function Adicionar(item As Produto) As Produto Implements IProdutoRepositorio.Adicionar Public Function Atualizar(item As Produto) As Boolean Implements IProdutoRepositorio.Atualizar Public Function GetPorID(id As Integer) As Produto Implements IProdutoRepositorio.GetPorID Public Function GetTodos() As System.Collections.Generic.IEnumerable(Of Produto) Implements IProdutoRepositorio.GetTodos Public Sub Remover(id As Integer) Implements IProdutoRepositorio.Remover
|
O repositório mantém a lista na memória local. Por ser mais simples fizemos assim neste exemplo mas em um aplicativo real, você iria armazenar os dados externamente, seja em um banco de dados ou no armazenamento em nuvem. Com o padrão repositório padrão, será mais fácil alterar a implementação mais tarde.
Definindo um novo Controller
Como já definimos o nosso modelo vamos agora definir um novo controlador para nossa aplicação.
Um controlador é um objeto que lida com requisições HTTP. O assistente para novo projeto cria dois controladores para você quando criamos o projeto. Para vê-los, expanda a pasta Controllers no Solution Explorer. São eles:
- HomeController : é um controlador ASP.NET MVC tradicional. É responsável por servir páginas HTML para o site, e não é diretamente relacionada à Web API;
- ValuesController : é um exemplo de controlador WebAPI;
Para criar um novo controlador clique com o botão direito sobre a pasta Controllers e selecione Add e a seguir Controller;
Na janela Add Controller informe o nome ProdutosController e selecione o template Empty API controller e clique no botão Add;
Obs: Cuidado para não Selecionar Empty MVC Controller
Um arquivo ProdutosController.vb será criado na pasta Controllers. Digite o código abaixo neste arquivo:
Imports System.Net Imports System.Web.Http Imports System.Net.Http Public Class ProdutosController Inherits ApiController Shared ReadOnly repository As IProdutoRepositorio = New ProdutoRepositorio() End Class |
O código define um campo que trata uma instância de IProdutoRepositorio.
Vamos agora implementar os métodos no controlador para os serviços que desejamos expor.
1- Método que obtém uma lista de produtos ( método HTTP GET , URI : /api/produtos )
Public Function GetAllProducts() As IEnumerable(Of Produto) Return repositorio.GetTodos() End Function |
O nome do método começa com "Get", então, por convenção, ele mapeia para solicitações GET. Além disso, o método não tem parâmetros, de modo que mapeia para um URI sem "id" no caminho.
2- Método que obtém um produto pelo seu Id ( método HTTP GET , URI : /api/produtos/id )
Public Function GetProduto(id As Integer) As Produto Dim item As Produto = repositorio.GetPorID(id) If item Is Nothing Then Throw New HttpResponseException(New HttpResponseMessage(HttpStatusCode.NotFound)) End If Return item End Function |
Este método também nome começa com "Get", mas o método tem um
parâmetro chamado ID. Este parâmetro é mapeado para o segmento "id" no caminho
URI. A ASP.NET Web API converte automaticamente o ID para o tipo de dados
correto (int) para o parâmetro.
O método getProduto lança uma exceção do tipo HttpResponseException
se o ID não for válido. Essa exceção será traduzida pelo Framework em erro 404
(não encontrado).
3- Método que obtém os produtos pela
categoria informada ( método HTTP GET , URI : /api/produtos?categoria=categoria
)
Public Function GetProdutosPorCategoria(categoria As String) As IEnumerable(Of Produto) Return repositorio.GetTodos().Where(Function(p) String.Equals(p.Categoria, categoria, StringComparison.OrdinalIgnoreCase)) End Function |
4- Método que cria um novo Produto
Para criar um novo produto, o cliente envia uma requisição HTTP POST, com o novo produto no corpo da mensagem da requisição.
Public Function PostProduto(item As Produto) As Produto item = repositorio.Adicionar(item) Return item End Function |
Para lidar com solicitações POST, vamos definir um método cujo nome começa com "Post". O método utiliza um parâmetro de tipo de produto. Por padrão, os parâmetros com tipos complexos são desserializados a partir do corpo da requisição. Portanto, esperamos que o cliente envie-nos uma representação serializada de um objeto produto, usando XML ou JSON para a serialização.
Esta implementação vai funcionar, mas ela não esta completa pois falta o seguinte:
Então vamos usar os recursos da ASP.NET Web API que torna fácil manipular a mensagem de resposta HTTP. A seguir temos uma implementação mais completa para o método acima:
Public Function PostProduto(item As Produto) As HttpResponseMessage item = repositorio.Adicionar(item) Dim response = Request.CreateResponse(Of Produto)(HttpStatusCode.Created, item) Dim uri As String = Url.Link("DefaultApi", New With { _ .id = item.Id _ }) response.Headers.Location = New Uri(uri) Return response End Function |
Observe que o tipo de retorno do método agora é HttpResponseMessage.
Ao retornar um HttpResponseMessage em vez de um produto, nós podemos
controlar os detalhes da mensagem de resposta HTTP, incluindo o código de status
e o cabeçalho Location.
O método CreateResponse cria um HttpResponseMessage e grava
automaticamente uma representação serializada do objeto produto no corpo da
mensagem de resposta.
5- Método que atualiza um produto
Public Sub PutProduto(id As Integer, produto As Produto) produto.Id = id If Not repositorio.Atualizar(produto) Then Throw New HttpResponseException(New HttpResponseMessage(HttpStatusCode.NotFound)) End If End Sub |
O nome do método começa com "Put", de forma que a Web API faz a correspondência para uma requisição PUT. O método tem dois parâmetros, a identificação do produto e o produto atualizado. O parâmetro id é retirado do caminho URI, e o parâmetro produto é deserializado a partir do corpo da requisição. Por padrão, o framework ASP.NET Web API toma os tipos de parâmetros simples da rota e os tipos complexos do corpo da solicitação.
6- Método que deleta um produto
Public Function DeletaProduto(id As Integer) As HttpResponseMessage repositorio.Remover(id) Return New HttpResponseMessage(HttpStatusCode.NoContent) End Function
|
De acordo com a especificação HTTP, o método DELETE deve ser idempotente, o que significa que as diversas requisições DELETE para a mesma URI tem que ter o mesmo efeito que uma simples requisição DELETE. Portanto, o método não deve retornar um código de erro se o produto já foi deletado.
Idempotente quer dizer que múltiplas requisições ao mesmo recurso usando o método devem ter o mesmo resultado que teria uma requisição apenas. A título de curiosidade, idempotente é a propriedade de um número que, multiplicado por ele mesmo, tem ele mesmo como resultado (n x n = n), em termos de números reais, apenas 0 e 1 têm essa propriedade. Em termos de métodos de requisição HTTP, os métodos GET, HEAD, PUT e DELETE são os que possuem a propriedade de ser idempotentes. (http://www.dicionarioinformal.com.br/idempotente/) |
Se uma solicitação DELETE for bem-sucedida, ela pode retornar o status 200(OK), com uma entidade de corpo que descreve o estado, o status 202(Aceito), se a exclusão ainda está pendente ou o status 204(No Content) sem corpo da entidade. Neste exemplo, o método retorna o status 204.
Dessa forma o código completo do nosso controlador ficou assim:
Imports System.Net Imports System.Web.Http Imports System.Net.Http Public Class ProdutosController Inherits ApiController Shared ReadOnly repositorio As IProdutoRepositorio = New ProdutoRepositorio() Public Function GetAllProducts() As IEnumerable(Of Produto) Return repositorio.GetTodos() End Function Public Function GetProduto(id As Integer) As Produto Dim item As Produto = repositorio.GetPorID(id) If item Is Nothing Then Throw New HttpResponseException(New HttpResponseMessage(HttpStatusCode.NotFound)) End If Return item End Function Public Function GetProdutosPorCategoria(categoria As String) As IEnumerable(Of Produto) Return repositorio.GetTodos().Where(Function(p) String.Equals(p.Categoria, categoria, StringComparison.OrdinalIgnoreCase)) End Function Public Function PostProduto(item As Produto) As HttpResponseMessage item = repositorio.Adicionar(item) Dim response = Request.CreateResponse(Of Produto)(HttpStatusCode.Created, item) Dim uri As String = Url.Link("DefaultApi", New With { _ .id = item.Id _ }) response.Headers.Location = New Uri(uri) Return response End Function Public Sub PutProduto(id As Integer, produto As Produto) produto.Id = id If Not repositorio.Atualizar(produto) Then Throw New HttpResponseException(New HttpResponseMessage(HttpStatusCode.NotFound)) End If End Sub Public Function DeletaProduto(id As Integer) As HttpResponseMessage repositorio.Remover(id) Return New HttpResponseMessage(HttpStatusCode.NoContent) End Function End Class
|
Assim demos mostramos a criação de uma nova WEB API que expõe os serviços para realizar as operações CRUD.
Na continuação deste artigo vamos implementar a interface (a view) para que possamos usar os recursos implementados de maneira amigável.
Pegue o projeto completo aqui: ProdutosRepositorio.zip (sem a pasta packages: Você deverá criar o projeto e substituir os arquivos principais)
Col 1:3
Graças damos a Deus, Pai de nosso Senhor Jesus Cristo, orando sempre por vós,Referências:
http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api