AngularJS: Consumindo Serviços RESTful
A maioria das SPA’s utilizam operações CRUD, e você provavelmente deve utiliza-las. Vamos a um simples exemplo.
No Angular.js temos dois serviços para enviar e recuperar dados de uma API através do verbo HTTP: o $http e $resource.
Meh… ambos retornam uma promise então porque eu deveria escolher um ao invés do outro?
$http Service
Vamos utilizar um simples código de exemplo:
Se nosso objetivo é apenas retornar uma lista de dados, esta tudo pronto, inclusive tratando possíveis erros. Inclusive, é possível trabalhar exatamente como na jQuery:
O Serviço $http
sem dúvidas é importante em aplicações Angular, principalmente pelo simples fato de poder encadear promises e ser absurdamente simples de utilizar.
Agora vamos pensar de uma outra forma: Imagine que você vai criar um serviço interagindo diretamente com uma API RESTful, então esse nosso serviço tera métodos utilizando $http.get
, $http.post
, $http.put
e $http.delete
certo?
Logo somos obrigados a escrever novos métodos, e isso se resume em mais código que as vezes pode ser considerado desnecessário. Porque não utilizamos isso de uma forma otimizada?
$resource Service
O Serviço $resource
nada mais é do que uma fabrica que nos permite interagir com API’s RESTful facilmente e é construido sobre o serviço $http
.
Talvez seja mais simples apenas mostrar um exemplo de código:
Dificil não?
Um porem é que o $resource
service diferente do $http
service não vem junto com o pacote do Angular… Porque?
Se analisarmos o simples fato que em nossa aplicação não é necessário algo como o $resource
, porque então carrega-lo?
Isso é algo interessante em SPA’s varia do framework, você não precisa utilizar tudo o que ela pode te proporcionar, apenas o que é interessante para a sua aplicação que talvez só precise de um simples $http.get
.
Em todo caso, para utilizar-mos o $resource
service precisamos adiciona-lo ao nosso projeto seja fazendo download do script ou adicionando o pacote angular-resource ao nosso projeto via Bower ou NPM.
Também precisamos injeta-lo no módulo principal da aplicação:
A API do $resource
service nos retorna alguns métodos como get, save, query, remove e delete.
- query(): Uma solicitação GET para o recurso
/api/users/
; - get(): Uma solicitação GET para o recurso
/api/users/:id
; - save(): Uma solicitação POST para o recurso
/api/users/
; - remove(): Uma solicitação DELETE para o recurso
/api/users/:id
; - delete(): Uma solicitação DELETE para o recurso
/api/users/:id
;
Você deve ter percebido que utilizamos :id
como parâmetro opcional que será utilizados com alguns dos verbos acima como por exemplo:
Simples não é?
Os métodos remove
e delete
fazem exatamente a mesma ação, porem, como nem tudo é um mar de rosas, em certas versões do IE o delete pode não funcionar por ser uma palavra reservada. Por esse motivo o remove
funciona como um alias para realizar a mesma ação.
Porem, ainda temos mais um goodie: Podemos utilizar alguns métodos que deixam nossas operações de CRUD ainda mais fáceis como $save
, $delete
e $remove
que nos retornam uma promise propriamente dita, o que facilita muito em alguns casos como neste exemplo:
Tudo muito bonito, tudo muito legal, mas vamos utilizar um exemplo que realmente faça sentido. Meu amigo @wbrunom desenvolveu uma API RESTful em Node como exemplo onde o tema principal são dragões, o link para a documentação pode ser visto aqui.
Vamos analisar nossos endpoints REST:
URL | Method | Params | Result |
---|---|---|---|
/api/dragons | GET | NULL | All entries |
/api/dragons/:slug | GET | NULL | Single entry |
/api/dragons | POST | JSON String | Entry Created |
/api/dragons/:slug | PUT | JSON String | Update Status |
/api/dragons/:slug | DELETE | NULL | Delete Status |
Vamos desenvolver um serviço para consumir esta API de forma simples:
Apenas para informar, quando utilizamos o angular.bootstrap
não fica mais necessário utilizar o ng-app em nossa aplicação. Assim conseguimos deixar nosso markup ainda mais limpo.
Sobre o HTML, utilizamos o ng-repeat
, o que não é novidade para ninguem, mas também foi adicionado o track by
, que é um parâmetro para otimizar o render dos elementos em loops como ng-repeat
e ng-options
.
O objetivo é atualizar os dados dragão, mas como no exemplo eu deixei apenas a informação do nome no input, referenciada no ng-model
. No método updateDragon
, disparado através do click do botão recebemos a informação do dragão relacionadas ao model, e como a entidade em si é um registro da nossa coleção dragons que veio do $resource
service, ele nos fornece de graça o método $save
, o que facilita o desenvolvimento de SPA. Certo?
Feito essas modificações em nosso controller, é a hora da verdade. Vamos atualizar um registro qualquer e ver o resultado.
Primeiramente precisamos entender que o $resource
não possui um método que realize PUT
nativamente. Na verdade, quando utilizamos os métodos query()
e get(:id)
, eles nos retornam uma coleção ou objeto do tipo Resource, o qual nativamente conta com alguns métodos especiais de entidade como $save()
, $delete()
e $remove()
.
O método $save()
realiza um POST
, o que funciona caso o recurso não exista na API, porém quando update, o servidor precisa checar e realizar uma espécie de create or update como existe no activerecord Rails.
Os método $delete()
e $remove()
realizam requisições do tipo DELETE
. Entretando, isso só funciona desde que nós informamos a referência em nosso recurso.
O segundo parametro é um objeto que indica o que será mapeado no endpoint a cada vez que um método especial da entidade for executado. Nesse caso foi associado que nosso :slug
estará relacionado a propriedade @slug
.
Feito isso agora nosso método $save
ira apontar para o slug caso nosso recurso possua o atributo slug, do contrário podemos criar uma nova entidade utilizando nosso dragonsService, o que ira lhe lembrar muito uma Classe
ou Model
:
Se funciona? Mas é claro que sim.
Foi criado um novo registro na API, o qual o slug é meu-dragao
, e isso é ótimo caso seja utilizado da maneira correta, mas ainda não resolvemos o problema do update certo?
Como citei anteriormente, não possuimos um método o qual execute PUT
, então a unica coisa que falta é o update. Para realizarmos essa operação, nós precisamos modificar nosso resource e deixa-lo mais customizável. Vejamos como:
O terceiro parametro é um objeto que nos permite adicionar quantos métodos especiais forem necessários para a aplicação utilizando o prefixo $
.
Agora que temos disponível o método $update
, vamos coloca-lo em uso:
Note que o retorno da API não é o registro atualizado, nem nada do tipo. Então nesse caso para atualizarmos a view, seria interessante ter um método que realiza novamente um GET
para atualizar nossa view.
Você pode ver a minha versão com esses métodos já implementados, porem o mais interessante seria criar métodos que iriam atuar dentro do próprio recurso para a realização do CRUD junto as validações necessárias e utiliza-las. Dessa forma criamos um padrão de assinatura de recurso em toda a aplicação aonde podemos utilizar promises através do $q
e deixar nosso código mais legível e com o minimo possível de lógica nos controllers.
Existem ainda várias possibilidades para se utilizar o $resource
, mas isso sera abordado com o tempo.
Espero que tenham entendido o conceito e as diferenças entre $resource
e $http
.
Join the Conversation