Web Services REStful

Para utilizar bem uma determinada tecnologia é preciso conhecer os seus fundamentos, os conceitos nos quais ela é construída e, principalmente, como os diversos elementos que a compõem se relacionam. Neste artigo serão apresentados os fundamentos de como os web services RESTful funcionam e quais os elementos necessários para desenvolver e executar esses serviços, tudo isso de maneira objetiva e utilizando exemplos simples, de modo que seja fácil compreender o seu processo de criação e desenvolvimento.

As aplicações e sistemas desenvolvidos hoje em dia precisam atender a certas condições do cenário atual, tanto no caso de usuários individuais quanto para o caso de organizações, ou usuários corporativos. Essas condições dizem respeito às características de execução dos softwares de forma distribuída, rápida, segura, portável e confiável.

Considerando que as empresas precisam que seus colaboradores possam acessar informações para desempenhar as suas atividades de maneira rápida, segura e de qualquer lugar, seja de dentro ou fora de suas dependências, os sistemas precisam levar em consideração essas características e, portanto, estarem preparados para ambientes de uso e execução distribuídos e heterogêneos. Além de prover acesso a dados e serviços aos seus colaboradores, existe o caso de empresas que formam parcerias, necessitando realizar a troca de informações entre os seus sistemas de gerenciamento e os sistemas de seus parceiros. Uma terceira situação diz respeito a empresas ou entidades que fornecem serviços direto a seus clientes. Nesse caso, eles precisam ter acesso tanto às informações quanto aos serviços disponibilizados, seja para que eles possam realizar uma compra ou mesmo tirar dúvidas a respeito da utilização de um produto adquirido.

Esta breve exposição a respeito de alguns cenários de interação entre colaboradores, clientes, parceiros, empresas e os seus respectivos sistemas de software serve para caracterizar as necessidades de execução já elencadas e que são exigidas das aplicações. Uma das características mais importantes entre as que fazem parte dos requisitos dos sistemas atualmente é a sua disponibilidade de operação em um ambiente distribuído, que é caracterizado pelo fato de que uma solução não é mais pensada para ser executada em um único computador, mas sim em diversas máquinas simultaneamente, atendendo a diferentes tipos de consultas, atividades ou serviços, e, na maioria dos casos, a partir de equipamentos completamente distintos uns dos outros, como notebooks, celulares e computadores desktop. Portanto, além do acesso distribuído, o sistema de software deve ser portável para diferentes plataformas, tanto de hardware quanto de software, pois além das diferenças já enumeradas, as máquinas podem estar utilizando sistemas operacionais diferentes, como Android, MacOS, Windows e Linux.

As condições de uso das aplicações, levando em consideração as situações apresentadas, requerem o uso de soluções tecnológicas que permitam aos desenvolvedores entregar as soluções de forma rápida, confiável e com baixo custo. Uma das tecnologias que permite isso são os web services, que podem ser definidos como aplicações cliente/servidor que se utilizam da comunicação através da internet, por meio do protocolo HTTP (HyperText Transfer Protocol), para prover serviços entre softwares que estejam executando em diferentes plataformas. Essas aplicações fazem uso do padrão XML (eXtensible Markup Language) para prover descritores que são interpretados automaticamente por outros sistemas, permitindo assim que diversos programas simples possam interagir uns com os outros para, em conjunto, fornecer soluções mais complexas e sofisticadas.

É importante entender que web service é um tipo de arquitetura de desenvolvimento cujo objetivo é a troca de informações entre duas entidades de software através da internet, utilizando os protocolos de comunicação disponíveis e tornando, assim, o envio e recepção dos dados um processo já consolidado e conhecido. As entidades de software envolvidas nesse processo de comunicação são aplicações consideradas como servidor quando seu objetivo é prestar um serviço ou fornecer um mecanismo de acesso a um conjunto de dados. Já as aplicações consideradas como cliente têm como objetivo consumir um ou mais serviços disponibilizados pelos servidores.

Portanto, agora é possível compreender melhor o significado do termo web service, que pode ser entendido como um “serviço” correspondente a um componente de software acessível através de um endereço ou ponto de rede. Para isso, tanto o consumidor quanto o provedor do serviço utilizam mensagens com um formato próprio para enviar requisições e receber as respostas sem fazer qualquer suposição quanto às capacidades ou tipo de tecnologia empregada tanto numa ponta quanto na outra do processo de comunicação.

A característica que diz respeito a não fazer distinção nem exigir uma determinada tecnologia para qualquer um dos envolvidos no processo de troca de mensagens é que confere aos web services a grande vantagem e aceitação como base no desenvolvimento de sistemas a serem utilizados em ambientes distribuídos e heterogêneos, como os encontrados em sistemas das mais diferentes áreas hoje em dia.

Os web services podem ser implementados de muitas maneiras diferentes, cada uma com vantagens e desvantagens próprias da solução técnica adotada. Em sistemas desenvolvidos se utilizando a linguagem Java existem duas soluções, que na documentação da Oracle; são denominadas como Big Web Services e RESTful Web Services. Tanto os web services Big quanto os RESTful fazem parte da API Java para XML (Java API for XML — JAX), que foi introduzida ao Java SE na versão 5.

A solução denominada Big Web Services é baseada na troca de mensagens codificadas em XML e utiliza o Protocolo de Acesso Simples a Objetos (Simple Object Access Protocol — SOAP), cujo padrão é mantido pela W3C. Esses serviços normalmente proveem um arquivo contendo a descrição padronizada das operações oferecidas, escrito seguindo a Linguagem de Descrição de Web Services (Web Services Description Language — WSDL), que, por sua vez, é um padrão definido em XML e utilizado para especificar interfaces de software que podem ser interpretadas pelos possíveis clientes. O propósito dessas declarações é que seja possível verificar se determinado serviço ou recurso é fornecido pelo web service em questão, além de descrever como deve ser realizado o acesso a esse serviço. Por utilizar o protocolo SOAP, os Big Web Services também são conhecidos como Web Services SOAP.

Já os web services RESTful (Representational State Transfer) são mais adequados para a utilização em cenários mais básicos, e também são melhor adaptados ao uso do protocolo HTTP do que os serviços SOAP. Os serviços RESTful são mais leves, o que significa que podem ser desenvolvidos com menor esforço, tornando-os mais fáceis de serem adotados como parte da implementação de um sistema.

O desenvolvimento de um web service RESTful é apropriado quando não é necessário manter informações de estado entre chamadas do serviço. Além disso, se as respostas fornecidas podem ser armazenadas em um sistema de cache para melhorar o desempenho global do sistema e como não há uma descrição formal do funcionamento do serviço, tanto a aplicação que corresponde ao servidor do serviço quanto a que corresponde ao cliente ou o consumidor do serviço precisam entender e concordar com o contexto da troca de informações que ocorre quando são realizados acessos aos recursos disponíveis no web service.

Ao levar essas características em consideração, é possível entender uma distinção na aplicabilidade e uso dessas duas maneiras de implementar web services. Os Big Web Services são utilizados em aplicações corporativas que possuem requisitos tanto de qualidade quanto de segurança e performance mais avançados. Já os web services RESTful são mais indicados para a integração de sistemas através da internet, conferindo às soluções qualidades como escalabilidade, simplicidade e fraco acoplamento entre as partes.

No restante deste artigo serão fornecidos mais detalhes de como os web services RESTful são estruturados e implementados, além de serem abordados também tópicos a respeito das dependências de recursos externos, como bibliotecas e APIs necessárias durante o desenvolvimento e implantação dos serviços.

Padrão RESTful

O padrão REST determina como deve ser realizada a Transferência de Estado Representacional (Representational State Transfer — REST), ou seja, a representação que corresponde ao conjunto de valores que representa uma determinada entidade em um dado momento. Essa transmissão de estados se dá a partir da especificação de parâmetros, em alguns casos chamados de restrições, que podem ser aplicados a web services. Quando isso ocorre, o que se obtém são serviços escaláveis, de fácil modificação e manutenção, e que apresentam boa performance, tornando esses serviços adequados a serem utilizados através da internet. Outra característica do padrão REST é que a aplicação fica limitada a uma arquitetura cliente/servidor na qual um protocolo de comunicação que não mantenha o estado das transações entre uma solicitação e outra deve ser utilizado.

Nos serviços RESTful, tanto os dados quanto as funcionalidades são considerados recursos e ficam acessíveis aos clientes através da utilização de URIs (Uniform Resource Identifiers), que normalmente são endereços na web que identificam tanto o servidor no qual a aplicação está hospedada quanto a própria aplicação e qual dos recursos oferecidos pela mesma está sendo solicitado.

Os recursos disponíveis em um serviço RESTful podem ser acessados ou manipulados a partir de um conjunto de operações predefinido pelo padrão. As operações possibilitam criar (POST), ler (GET), alterar (PUT) e apagar (DELETE) recursos, e estão disponíveis a partir de mensagens utilizando o protocolo HTTP. Ao receber uma solicitação, ou mensagem HTTP, todas as informações necessárias para a realização da transação estão inclusas, não sendo necessário salvar informações para requisições de serviço futuras, o que resulta em aplicações simples e leves do ponto de vista do desenvolvedor. Já para os usuários que utilizam sistemas baseados em web services RESTful, são serviços com um bom desempenho e transparentes, considerando sua utilização. Isso quer dizer que além de as solicitações aos serviços apresentarem boa responsividade, de acordo com a infraestrutura disponível, os usuários não fazem muita distinção entre um sistema executando localmente ou em um servidor de aplicação. Além dessas qualidades, a adoção do RESTful também tem impacto sobre outras métricas de qualidade de software, por exemplo: a facilidade de uso da aplicação e o tempo necessário pelo usuário para aprender a utilizá-la.

Outra característica importante dos recursos no padrão RESTful é que esses são dissociados de sua representação, ou seja, a maneira como os dados são manipulados na implementação do serviço não está vinculada ao formato da resposta a ser fornecida a uma solicitação, o que permite que os clientes peçam os dados em uma grande variedade de formatos, como HTML, XML, texto puro, PDF, JPG, entre outros.

Todas as características discutidas até aqui, que são parte do padrão RESTful, são adicionadas ao serviço utilizando-se anotações no código, de maneira que, a partir delas, o servidor de aplicações possa interpretar as URIs que recebe e direcionar a mensagem ao método correspondente do web service que o cliente deseja acessar. Essas anotações devem seguir as definições da API JAX-RS para determinar quais ações podem ser realizadas em cada recurso disponibilizado. A API JAX-RS especifica um conjunto de anotações de tempo de execução, portanto a ligação do servidor de aplicações com os recursos do web service acontece quando o pacote com as classes que o implementam é carregado no servidor. A hospedagem, ou publicação, de web services RESTful pode ser realizada em diferentes servidores de aplicação, como o GlassFish, Apache Tomcat e Oracle WebLogic.

Para que o servidor de aplicações possa prover serviços RESTful, além da implementação do próprio serviço, é necessário também que esteja disponível a implementação da API JAX-RS, na qual estão disponíveis os serviços e as classes que definem as anotações e os seus correspondentes comportamentos, tornando possível a ligação entre as solicitações dos clientes e os recursos do web service publicado. A implementação de referência da API JAX-RS é o Jersey, um projeto de código aberto, portável, com qualidade, que está agora em sua versão 2.23 e que contempla as JSRs 311 e 339, que dizem respeito aos web services RESTful.

Passos para criar um web service RESTful

Para criar um web service RESTful é necessário implementar uma classe para servir de base para os recursos a serem acessados pelos clientes. Essa classe é um POJO (Plain Old Java Object — veja o BOX 1) que possui a anotação (veja o BOX 2) @Path em nível de classe ou pelo menos em um de seus métodos, ou ainda um método anotado com uma designação de método de pedido (request method designator), que pode ser @GET, @PUT, @POST ou @DELETE.

O padrão RESTful faz uso de anotações para facilitar o desenvolvimento dos web services, de modo que a declaração dos recursos e ações que poderão ser realizadas sejam especificadas utilizando esses metadados nos membros da classe. Algumas das anotações mais utilizadas, definidas pela API JAX-RS, estão listadas na Lista 1, juntamente com uma breve explicação a respeito do seu significado e de como são inseridas no código.

BOX 1. POJO

Quando se diz que uma classe Java é um POJO, significa que ela segue o conceito de “quanto mais simples melhor”, ou seja, não possui uma regra específica para a sua codificação e também não utiliza os recursos de herança da Orientação a Objetos para estender uma classe já existente. Dessa maneira, o objeto resultante dessa classe deve possuir apenas os atributos e funcionalidades mínimos para atender aos requisitos especificados para a classe, sem a necessidade de atender a regras de nomenclatura de métodos e atributos, como no caso dos JavaBeans.

De forma simplificada, o termo POJO é utilizado para designar as classes Java que não seguem as regras de algum padrão ou framework, ou seja, as classes puras e simples. O nome foi criado por Martin Fowler, Rebecca Parsons e Josh MacKenzie em setembro de 2000 para facilitar o uso de objetos simples e regulares pelos programadores e analistas em seus projetos.

Estritamente falando, um POJO não deve estender uma classe, não deve implementar interfaces e não deve utilizar anotações em nível da classe, de atributos ou de métodos. Porém, em alguns casos, existem padrões de desenvolvimento que especificam o uso de anotações e declaram que as classes são POJOs, o que pode ser considerado como aceitável se a classe anotada foi um POJO antes da inclusão das anotações e volta a ser caso as anotações sejam retiradas. Nesse caso, a classe pode ser aceita como sendo um POJO, pois não possui outras características que a definam como sendo uma classe ou objeto especializado (SJO — Specialized Java Object).

BOX 2. Anotações

Uma anotação é uma informação a respeito de um dos componentes de uma classe ou da própria classe, ou seja, é um metadado (dados a respeito dos dados, ou seja, dados que descrevem ou caracterizam outros dados). As anotações são um recurso incluído na especificação da linguagem Java a partir de sua versão 5 com o objetivo de facilitar a documentação do código, rastrear dependências entre entidades do sistema e também possibilitar a execução de verificações em tempo de compilação.

A inclusão de uma anotação no código Java utiliza o símbolo `@` seguido do nome da anotação e, quando for o caso, de um conjunto de parâmetros no formato nome=valor separados por vírgula.

Um exemplo simples, que faz parte da API Java, é a anotação @Override, que informa ao compilador que o método anotado é uma sobrescrita de outro método. A partir dessa informação o compilador pode efetuar uma verificação adicional para determinar se a declaração do método está correta, o que não seria possível sem a indicação de que o mesmo está sobrescrevendo uma funcionalidade de uma de suas superclasses.

As anotações também são utilizadas por frameworks para adicionar características ao código que serão utilizadas em tempo de compilação ou de execução para produzirem, por exemplo, as informações de configuração necessárias ou para criar elementos externos, como tabelas em uma base de dados, entre muitas outras possibilidades.

@Path

Informa o valor de uma URI relativa, que determina o caminho no qual a classe ou método será hospedado no servidor. Além da especificação do caminho do recurso é possível também incluir a definição de variáveis nas URIs, como o nome do usuário manuseando o sistema ou os parâmetros a serem utilizados durante a execução da requisição enviada pelo cliente.

@GET

Essa anotação é um designador de método de pedido (Request Method Designator), que corresponde ao método HTTP de mesmo nome, e determina que o método da classe anotado processe e responda às solicitações GET recebidas. O resultado esperado é que o serviço retorne o valor correspondente ao recurso solicitado, que pode ser o conteúdo de um atributo, os registros de uma tabela em uma base de dados, o resultado de algum cálculo, entre outras possibilidades.

@POST

Essa anotação também é um designador de método de pedido e determina que o método da classe anotado processe e responda às solicitações POST recebidas. Como resultado de uma requisição POST é esperada a alteração do valor ou estado de algum recurso disponibilizado pelo serviço, que pode ser um registro em uma base de dados, o conteúdo de um arquivo, entre outros.

@PUT

Essa anotação também é um designador de método de pedido e determina que o método da classe anotado processe e responda às solicitações PUT recebidas. O uso de uma requisição PUT objetiva a criação de um recurso pelo serviço, que pode ser um arquivo, um registro em um arquivo ou em uma base de dados, entre tantas outras situações possíveis.

@DELETE

Esta anotação também é um designador de método de pedido e determina que o método da classe anotado processe e responda às solicitações DELETE recebidas. O resultado esperado para uma requisição DELETE é a eliminação ou destruição do recurso correspondente, ou seja, corresponde à eliminação do conteúdo de um registro em uma base de dados ou à remoção de um arquivo de dados, conforme a especificação utilizada na implementação do serviço.

@PathParam

Essa anotação designa um parâmetro que está na URI de requisição do serviço. O nome e posição dos parâmetros na URI são determinados pelo modelo definido pela anotação @Path.

@QueryParam

Essa anotação designa um parâmetro que está na parte de parâmetros de busca da URI enviada pelo cliente. Os parâmetros definidos dessa forma não necessitam estar especificados no modelo da URI definido pela anotação @Path.

@Consumes

É uma anotação para especificar o tipo de dado que um recurso pode consumir, ou seja, que o cliente pode enviar ao serviço. Os tipos de dados dessa anotação são especificados usando-se os tipos do padrão MIME.

@Produces

Essa é uma anotação para especificar o tipo de dados que um recurso pode produzir e enviar para o cliente em resposta a uma solicitação. Os tipos de dados dessa anotação também são especificados usando-se os tipos do padrão MIME.

Lista 1. Descrição das anotações da API JAX-RS.

Nas próximas seções serão apresentados e explicados um conjunto de exemplos com o objetivo de criar um web service RESTful simples. O primeiro exemplo envolve a criação do projeto, sua configuração e a codificação de um recurso que apenas responde a uma requisição HTTP GET com a frase “Olá mundo!”, com o objetivo de entender a estrutura do projeto, seus componentes e as ligações entre os mesmos. Os exemplos seguintes acrescentarão novos recursos e funcionalidades ao POJO inicial para demonstrar diferentes maneiras de receber e enviar dados para o cliente.

O ambiente utilizado para o desenvolvimento dos exemplos a seguir envolve a IDE Eclipse Mars 2 (4.5.2), o servidor Apache Tomcat v7.0 e o framework Jersey versão 1.19.1. Ao selecionar a versão do Eclipse, verifique se a mesma é destinada à aplicação Java EE. Caso não seja, será necessário instalar os plugins e componentes correspondentes ao desenvolvimento de aplicações nessa plataforma para que seja possível trabalhar com o desenvolvimento de web services RESTful no mesmo. Ademais, durante o processo de implementação dos exemplos, o servidor Tomcat será iniciado a partir do Eclipse, portanto, ao instalá-lo, não informe que deseja iniciar o serviço automaticamente. Por último, os arquivos que compõem o framework Jersey devem ser vinculados a cada projeto individualmente, para garantir que o mesmo esteja disponível em tempo de execução quando o serviço for publicado no servidor de aplicações.

Implementando um web service RESTful básico

Para iniciar o desenvolvimento de um web service no Eclipse é necessária a criação de um Projeto Web Dinâmico (Dynamic Web Project). Feito isso, devem ser informados os dados a respeito do servidor no qual a aplicação será hospedada. Conforme já mencionado, nesse exemplo será utilizado o Apache Tomcat (vide Figura 1). Essas informações podem ser alteradas no futuro para verificar a compatibilidade com outros servidores, como o GlassFish. Os dados de configuração são utilizados pelo ambiente para publicar o web service, assim como para iniciar e parar o servidor propriamente dito.

Além das configurações a respeito do servidor, é necessária a criação de um arquivo XML com as informações a respeito do web service que será publicado, contendo o nome do web service, o nome do pacote no qual as classes Java estão codificadas, bem como o nome da aplicação, que será a base do caminho nas URIs enviadas nas solicitações dos clientes. Na última etapa de criação do projeto no Eclipse existe a opção correspondente à criação desse arquivo, (Generate web.xml deployment descriptor).

Configuração
de um projeto Web Dinâmico para implementar um web service no Eclipse
Figura 1. Configuração de um projeto Web Dinâmico para implementar um web service no Eclipse.

Uma vez criado o projeto, pode-se então incluir recursos Java, ou seja, o POJO no qual as funcionalidades do web service serão implementadas. Para isso, é necessário antes criar um pacote para abrigar as classes do web service, cujo nome o servidor Tomcat utiliza para buscar os recursos do serviço ao responder às requisições HTTP dos clientes. É preciso também adicionar ao projeto os arquivos JAR do framework Jersey para que tanto as anotações quanto as demais funcionalidades do mesmo possam ser utilizadas.

Na Figura 2 é exibida a estrutura lógica do projeto, na qual estão destacados o pacote a ser utilizado e os arquivos correspondentes à API Jersey. No caso do Jersey, os arquivos foram copiados para a pasta WebContent/WEB-INF/lib, onde devem ser colocados todos os arquivos correspondentes às bibliotecas e APIs externas das quais o serviço fará uso durante a sua execução no ambiente do servidor de aplicações.

Entre os serviços executados pelos componentes do framework Jersey está o tratamento de identificação das requisições HTTP recebidas pelo servidor, ou seja, a partir da URI e da identificação do tipo de requisição (GET, PUT, etc.) o framework identifica qual é a aplicação (web service) para a qual o cliente direcionou a requisição, e, entre os diferentes recursos disponibilizados pelo web service, qual é o que deve ser executado.

A identificação dos recursos do web service no código é feita com o uso das anotações apresentadas na Lista 1, entre outras mais, que estão disponíveis no framework. Na requisição do cliente os recursos são identificados a partir dos nomes existentes no caminho da URI utilizada na requisição do serviço.

Estrutura lógica dos componentes de um Dynamic Web Project
Figura 2. Estrutura lógica dos componentes de um Dynamic Web Project.

Para esse exemplo, a classe do web service deve conter apenas um recurso, que irá responder a requisições GET enviadas pelos clientes, devolvendo a frase “Olá Mundo!”. Na Listagem 1 é apresentado o código para o POJO que implementa esse recurso. Os pontos importantes para o web service nesse código são os seguintes: o nome do pacote no qual a classe é definida, pois esse nome será informado ao servidor de aplicação para que ele possa localizar corretamente os recursos; e a anotação @Path("servico") em nível de classe, que informa que todos os recursos implementados nessa classe serão acessados usando o nome fornecido como parâmetro à anotação, na URI. Isso quer dizer que quando o cliente desejar acessar algo que está implementado nessa classe, ele deve fazer isso utilizando uma URI que contenha o nome de caminho ao nível de classe seguido do nome do recurso, por exemplo: /servico/[nome do recurso].

O nome da classe não é relevante para o acesso ao web service, ao contrário dos valores passados às anotações para configurar os caminhos parciais de cada recurso, pois o servidor de aplicação não conhece os nomes das entidades declaradas no código Java, mas sim as informações armazenadas a partir dos parâmetros enviados às anotações do padrão RESTful.

Como base para todos os recursos disponíveis no web service, é utilizado o nome do projeto. Em seguida, considerando que em um projeto Web Dinâmico pode existir mais de um POJO, da mesma maneira que ocorre em projetos Java EE, eles são diferenciados um do outro na URI fornecida ao servidor de aplicação através do nome informado na anotação @Path, em nível de classe. Essa característica pode ser utilizada, por exemplo, para criar conjuntos de recursos, como o acesso a diferentes tabelas em uma base de dados, sendo o acesso a cada uma delas implementado por um POJO diferente, dado que todos fazem parte do mesmo projeto Java.

Listagem 1. Web service simples para atender a uma requisição HTTP GET.


  // Pacote no qual a classe que implementa o web service está localizada
  package mdmatrakas.webservice;
   
  // Importação das classes da API JAX-RS em uso no web service
  import javax.ws.rs.GET;
  import javax.ws.rs.Path;
  import javax.ws.rs.Produces;
  import javax.ws.rs.core.MediaType;
   
  // Caminho relativo para o serviço representado por esta classe 
  @Path("servico")
  public class WebServiceOla
  {
         // A anotação @GET indica que o método a seguir processa requisições HTTP GET
         @GET
         // A anotação @Path determina o caminho relativo do método
         // Como o método faz parte da classe WebServiceOla, que está hospedada no caminho "/servico",
         // o caminho relativo para acessar este método é "/servico/oi"
         @Path("oi")
         // A anotação @Produces informa o tipo de dado produzido pelo método e que será enviado ao 
         // cliente que realizou a solicitação HTTP GET. 
         // Neste caso o retorno será do tipo "Texto Puro"
         @Produces(MediaType.TEXT_PLAIN)
         // O método ola() implementa um recurso do web service
         public String ola()
         {
               // A String retornada por este método será enviada ao cliente que solicitou o recurso deste web service
               // a partir da URI ".../servico/oi" com uma requisição HTTP GET
               return "Olá mundo!";
         }
  }

Ao desenvolver um web service RESTful, uma parte importante do processo é a elaboração das URIs de acesso aos recursos. Alguns pontos importantes a serem considerados neste processo são elencados a seguir:

  • Usar substantivos no plural: A opção pelo plural facilita a identificação dos recursos nas URIs, evitando erros e simplificando a depuração da comunicação entre o cliente e o servidor.
  • Evitar o uso de espaços: Utilizar o caractere sublinhado (_) ou o hífen (-) ao utilizar nomes longos compostos por mais de uma palavra. Apesar da sequência “%20” poder ser utilizada nas URIs para designar a utilização de espaços, essa substituição nem sempre é realizada da maneira correta, gerando erros por falha na especificação da URI;
  • Utilizar letras minúsculas: Apesar das URIs serem sensíveis a maiúsculas e minúsculas, é uma boa prática manter todas as suas letras minúsculas, evitando erros de formação nas URIs, como no caso do uso do espaço;
  • Manter a retrocompatibilidade: Como os web services são serviços públicos, uma vez que uma URI tenha sido divulgada ela deveria estar sempre disponível. Caso seja necessário atualizar uma URI, a URI em desuso deveria ser redirecionada ao novo endereço utilizando o código de retorno 300 do protocolo HTTP;
  • Utilizar os comandos HTTP: Ao realizar operações nos recursos, utilizar as mensagens GET, PUT, POST e DELETE do protocolo HTTP. Não é uma boa prática utilizar nomes de operações nas URIs.

A seguir são listados alguns pontos importantes a serem considerados durante a modelagem ou representação dos recursos em um web service RESTful:

  • Compreensibilidade: Tanto o servidor quanto o cliente devem ser capazes de entender e utilizar a forma de representação do recurso;
  • Integralidade: O formato do dado a ser utilizado deve ser capaz de representar um recurso completamente, mesmo nos casos em que um recurso possa ser composto por outros recursos. Dessa forma, a representação adotada deve conseguir representar tanto recursos com estruturas simples quanto complexas, ou seja, caracterizar corretamente casos em que os dados que representam o recurso possuem um conjunto simples de valores e também os casos nos quais os mesmos apresentam, por exemplo, dados em mais de um nível, com dependências entre os valores de cada nível;
  • Acoplamento: Um recurso pode conter ligações com outros recursos. Sendo assim, a sua representação deve poder lidar com tais situações.

Nos web services disponíveis atualmente, os recursos são representados utilizando formatação tanto XML quanto JSON. A descrição de como representar recursos utilizando esses formatos não faz parte do escopo deste artigo, apesar de alguns dos exemplos implementados utilizarem a representação de recursos no formato XML.

A última etapa no processo de criação de web services RESTful é a alteração do arquivo web.xml (ou a sua criação, dependendo das opções no momento de criar o projeto no Eclipse). Esse arquivo possui as configurações de publicação do web service, sendo o seu conteúdo mostrado na Listagem 2.

As informações mais importantes desse arquivo são as seguintes:

  • Linha 11: Especificação da classe que implementa o servlet a ser utilizado na execução do web service. Essa classe faz parte do framework Jersey e é responsável por interpretar o conteúdo da solicitação HTTP e realizar a ligação com o método correspondente do web service;
  • Linha 14: Especificação do nome do pacote que contém a(s) classe(s) com os recursos do web service;
  • Linha 20: Especificação do caminho relativo para acessar os recursos desse web service. Nesse exemplo o caminho foi definido como “/*”, não acrescentando nomes na URI do web service. Portanto, o único recurso disponível é acessado a partir do nome do serviço, isto é, o nome do projeto (/WebServiceOla), seguido do caminho da classe (/servico/) e do nome do recurso (oi), formando a URI /WebService/servico/oi.

Listagem 2. Conteúdo do arquivo de configuração para o web service RESTful chamado WebServiceOla.


  01     <?xml version="1.0" encoding="UTF-8"?>
  02     <web-app 
  03            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  04            xmlns="http://java.sun.com/xml/ns/javaee" 
  05            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
  06            id="WebApp_ID" 
  07            version="3.0">
  08       <display-name>WebServiceOla</display-name>
  09       <servlet>
  10         <servlet-name>RESTful Service Ola</servlet-name>
  11         <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  12         <init-param>
  13           <param-name>com.sun.jersey.config.property.packages</param-name>
  14           <param-value>mdmatrakas/webservice</param-value>
  15         </init-param>
  16         <load-on-startup>1</load-on-startup>
  17       </servlet>
  18       <servlet-mapping>
  19         <servlet-name>RESTful Service Ola</servlet-name>
  20         <url-pattern>/*</url-pattern>
  21       </servlet-mapping>
  22     </web-app>

A classe da Listagem 1 e o arquivo de configurações da Listagem 2 caracterizam um web service simples, que já pode ser executado e testado. Entretanto, para que isso ocorra, é necessário que o mesmo seja publicado no servidor de aplicações, no caso o Apache Tomcat. As configurações fornecidas no momento da criação do projeto no Eclipse permitem que o mesmo realize os procedimentos exigidos pelo processo de publicação de forma automatizada, bastando então solicitar a execução da classe utilizando a opção executar no servidor (Run on Server).

Uma vez publicado o exemplo, e considerando que o servidor Apache está executando na mesma máquina na qual o web service está sendo implementado, ao fornecer a URI http://localhost:8080/WebServiceOla/servico/oi a um navegador web, o texto “Olá Mundo!” será exibido como resposta, como mostrado na Figura 3.

Resposta do recurso oi disponível no WebServiceOla
Figura 3. Resposta do recurso "oi" disponível no WebServiceOla.

Melhorando a formatação da resposta

Na Figura 3 o texto exibido pelo navegador não corresponde ao que foi produzido pela função que implementa o recurso oi do WebServiceOla, porque a codificação padrão dos navegadores é para texto em inglês, que não prevê o uso de caracteres acentuados. Uma maneira de melhorar a apresentação da resposta no navegador é criar um recurso que retorne uma página HTML com as informações de codificação corretas para o idioma utilizado nos textos, no caso o português brasileiro. O código correspondente à mesma funcionalidade, porém com o texto fazendo parte da página HTML, está na Listagem 3.

Caso os dois recursos sejam mantidos, o caminho de acesso a cada um deve ser único nas suas respectivas anotações @Path. Além disso, é preciso modificar o tipo de dado produzido pelo recurso na anotação @Produces, indicando "TEXT_HTML". O resultado desse recurso é apresentado na Figura 4.

Na string retornada pelo recurso deve estar codificada a página HTML com todas as informações relevantes e necessárias para a correta exibição do texto pelo navegador. Assim, as metainformações de conteúdo de texto e conjunto de caracteres do tipo UTF-8, no cabeçalho da página, alteram a codificação utilizada pelo navegador ao exibir esse conteúdo. Outra vantagem de utilizar uma página HTML para exibir as respostas em um navegador é a possibilidade de alterar a formatação do texto para enfatizar as informações mais importantes, ou para formatar um relatório dinâmico. Esses recursos são particularmente interessantes ao produzir relatórios a partir de buscas em bases de dados cujo acesso seja realizado por web services, ou para compor diferentes tipos de conteúdo em uma mesma resposta, por exemplo quando for necessário criar um texto com imagens.

Listagem 3. Produzindo uma página HTML no web service.

public class WebServiceOla
  {
  // código repetido omitido...
   
         @GET
         @Path("oi-html")
         @Produces(MediaType.TEXT_HTML)
         public String olaHtml()
         {
               return "<html lang=\"pt-br\">"
                             + "<head><META  http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">"
                             + "<title>Informações</title>"
                             + "</head>"
                             + "<body><h1>" 
                             + "Olá mundo!" 
                             + "</h1></body>" 
                             + "<html>";
         }
  }
Resposta do WebServiceOla utilizando formatação HTML
Figura 4. Resposta do WebServiceOla utilizando formatação HTML.

Neste exemplo, as respostas são exibidas em um navegador, mas na maioria das vezes os resultados serão processados por uma aplicação cliente, de forma automatizada. Quando isso acontece, é mais importante a estrutura e codificação dos dados do que sua formatação para exibição. Para esses casos, a utilização de um arquivo XML como resposta tem mais vantagens, pois facilita a interpretação das informações, além de ser de fácil tratamento em qualquer plataforma, tornando o web service mais robusto.

Enviar dados do cliente ao web service

Nas seções anteriores foram apresentados exemplos nos quais o web service produz informações para o cliente. A questão agora é como o cliente pode enviar dados a um web service para serem utilizados como parâmetros em um recurso. Para exemplificar essa situação, a seguir será demonstrada uma situação na qual a requisição irá realizar uma operação de soma entre dois valores informados pelo cliente.

Na Listagem 4 podemos ver o código com a implementação dessa nova funcionalidade no WebServiceOla. Os valores que serão somados devem ser enviados na URI de acesso após o nome do recurso, separados por “/”. Isso é possível ao adicionar os campos a serem interpretados como parâmetros na string passada para a anotação @Path, e depois utilizar esses campos em anotações @PathParam nas respectivas variáveis do método, conforme exposto nos comentários do código da Listagem 4.

Listagem 4. Enviando dados ao web service através da URI.

public class WebServiceOla
  {
         // código repetido omitido...
   
         // A anotação @GET indica que o método a seguir processa requisições HTTP GET
         @GET
         // A anotação @Path determina o caminho relativo do método, adicionando
         // dois nomes de parâmetros ao caminho: "a" e "b".
         @Path("soma/{a}/{b}")
         // A anotação @Produces informa que o retorno será do tipo "Texto Puro".
         @Produces(MediaType.TEXT_PLAIN)
         // O método soma() implementa um recurso do web service.
         // As anotações @PathParam indicam que os parâmetros serão fornecidos a partir da URI do
         // recurso.
         public String soma(@PathParam("a") int a, @PathParam("b") int b)
         {
               return String.valueOf(a + b);
         }
  }

Como esse método também implementa uma resposta a uma requisição HTTP GET, é possível testar a sua execução utilizando um navegador web normalmente, como apresentado na Figura 5.

Resposta do recurso soma
Figura 5. Resposta do recurso "soma".

Porém, como já mencionado, quando se deseja enviar dados para o servidor com o objetivo de atualizar um registro, por exemplo, o recomendado é utilizar uma mensagem HTTP PUT ou HTTP POST.

Na Listagem 5 é exibido o código para o tratamento de uma mensagem PUT. Nesse exemplo é enviado apenas um parâmetro ao recurso do web service, também através da URI. A única diferença entre os métodos soma() (Listagem 4) e criaRegistro() (Listagem 5) é a utilização da anotação @PUT para indicar que o segundo será utilizado através da mensagem correspondente no protocolo HTTP. Como não é possível enviar uma mensagem HTTP PUT a partir dos navegadores web, é necessário utilizar uma ferramenta externa para testar o funcionamento do novo recurso do web service Ola.

Listagem 5. Enviando dados ao web service através da URI utilizando uma requisição PUT.

public class WebServiceOla
  {
         // código repetido omitido...
                             
         // A anotação @PUT indica que o método a seguir processa requisições HTTP PUT.
         @PUT
         // A anotação @Path determina o caminho relativo do método, adicionando
         // o parâmetro "registro" ao caminho. 
         @Path("enviar/{registro}")
         @Produces(MediaType.TEXT_PLAIN)
         public String criaRegistro(@PathParam("registro") String registro)
         {
               // Aqui deve ser incluído o código para criar o registro solicitado.
               return "Registro: \''" + registro + "\'' criado com sucesso!";
         }
  }

Existem alguns aplicativos capazes de enviar diferentes mensagens HTTP, como PUT, POST DELETE, entre outras. Na Chrome Web Store, dois apps de uso bastante simples e que podem ser instalados como extensões para o navegador Google Chrome são o Advanced Rest Client e o POSTMAN. Eles podem ser utilizados para testar as mensagens HTTP para os exemplos deste artigo.

Na Figura 6 é apresentado o resultado ao enviar o comando HTTP PUT para a URI do recurso implementado na Listagem 5, utilizando o Advanced Rest Client. Estão destacados nessa imagem a URI do recurso solicitado, o tipo de mensagem HTTP e a resposta enviada pelo servidor para essa solicitação. Não faz parte do escopo deste artigo descrever o funcionamento dessas aplicações clientes, que podem ser utilizadas para testar as mensagens HTTP e depurar os web services e seus recursos, até porque seu uso é bastante simples e intuitivo.

Resposta a uma requisição PUT
Figura 6. Resposta a uma requisição PUT.

De acordo com as descrições fornecidas na Lista 1, as mensagens HTTP PUT são utilizadas para criar ou armazenar um novo valor no servidor. Já as mensagens do tipo POST são utilizadas para atualizar valores. Com relação a isso, aqui cabe uma nota: a operação de atualização também pode ser interpretada de maneira que seja possível realizar a criação de um novo valor, que pode ser, por exemplo, um novo registro em uma base de dados ou qualquer tipo de objeto que o web service venha a criar, isto é, uma requisição POST pode ser utilizada tanto para atualizar quanto para criar um novo registro/valor. Portanto, cabe ao desenvolvedor determinar se uma mensagem POST pode apenas atualizar um valor já existente, ou, no caso de ser solicitado a alterar um valor que ainda não existe, realizar a sua criação. Qualquer uma das duas soluções está correta e deve ser documentada na descrição dos recursos expostos pelo web service.

Na Listagem 6 está a implementação do método que responde à mensagem POST simulando a atualização do registro solicitado. Novamente é interessante notar que não há muitas diferenças no código, apenas a alteração da anotação @PUT para @POST, inclusive mantendo o mesmo caminho na anotação @Path, o que não causa problemas, pois os caminhos, apesar de serem os mesmos, são utilizados para atender a requisições diferentes. Neste caso, o uso do mesmo caminho facilita a interação com o serviço, pois o significado de “enviar” dados é complementado pelo tipo de requisição HTTP, sendo uma para criar um novo registro (PUT) e outra para atualizar um registro já existente (POST).

Listagem 6. Enviando dados ao web service através da URI utilizando uma requisição POST.

public class WebServiceOla
  {
  // código repetido omitido...
   
         // A anotação @POST indica que o método a seguir processa requisições HTTP POST
         @POST
         @Path("enviar/{registro}")
         @Produces(MediaType.TEXT_PLAIN)
         public String atualizaRegistro(@PathParam("registro") String registro)
         {
               // Aqui deve ser incluído o código para atualizar o registro solicitado.
               return "Registro: \''" + registro + "\'' atualizado com sucesso!";
         }
  }

Segundo a documentação do padrão JAX-RS e da linguagem Java, tanto métodos assinados com @PUT quanto com @POST podem ser utilizados para criar ou alterar valores. Como o tratamento de mensagens POST pode significar qualquer coisa, cabe à aplicação determinar o seu significado. Já uma mensagem PUT possui uma semântica bem definida para criar e atualizar um recurso. Assim, a representação que um cliente envia em uma requisição PUT deve ser a mesma representação obtida utilizando uma requisição GET para o mesmo tipo de mídia (MediaType), o que não é obrigatório em uma requisição POST.

Devido a essas restrições, uma requisição PUT não permite que um recurso seja alterado parcialmente, ou seja, não é possível enviar dados parciais para um determinado elemento. O cliente deve enviar o objeto completo, com a mesma representação da requisição GET.

Enviando parâmetros como valores de busca

Quando um cliente envia ao servidor uma requisição que necessita de parâmetros, esses, além de serem posicionados na URI como variáveis, também podem ser especificados como parâmetros de busca. Ao definir uma URI, os parâmetros de busca são posicionados ao seu final após um caractere de interrogação (?), utilizando-se pares chave-valor para cada parâmetro. Com esse tipo de construção não é necessário especificar os nomes dos parâmetros na anotação @Path da maneira como foi feito nos exemplos das Listagens 4, 5 e 6, mas o cliente deve especificar o nome de cada um dos parâmetros de busca utilizando exatamente o mesmo nome que o web service está esperando.

Para receber esse tipo de parâmetro é utilizada a anotação @QueryParam, que informa que os valores estão codificados como parâmetros de busca na URI e não como parte do caminho. Para ilustrar o uso de um parâmetro de busca, o exemplo da requisição PUT foi reescrito na Listagem 7.

Listagem 7. Enviando dados ao web service através de um parâmetro de busca.

public class WebServiceOla
  {
  // código repetido omitido...
   
         @PUT
         // A anotação @Path determina o caminho relativo do método
         @Path("enviar")
         @Produces(MediaType.TEXT_PLAIN)
         // A anotação @QueryParam informa que o parâmetro esperado por este método será recebido
         // como um parâmetro de busca na URI: "servico/enviar?registro=valor"
         public String criaRegistroQuery(@QueryParam("registro") String registro)
         {
               // Aqui deve ser incluído o código para criar o registro solicitado.
               return "Registro: \''" + registro + "\'' criado com sucesso!";
         }
  }

Para enviar mais de um parâmetro de busca, os mesmos devem ser separados uns dos outros utilizando-se o caractere “&”. Portanto, se os valores para “idade” e “nome” fossem esperados pelo servidor, a URI de busca seria: webservice/recurso?idade=15&nome=Fulano. Nesse caso a ordem dos valores não é importante, pois a busca é feita pelo seu nome. Ademais, para cada parâmetro de busca é possível especificar um valor padrão com a anotação @DefaultValue("valor"). Esse será o valor atribuído à variável correspondente caso o parâmetro não esteja especificado na string enviada pelo cliente.

Outro ponto importante a ser levado em consideração ao trabalhar com parâmetros de busca, da mesma forma que valores codificados no caminho da URI, é o uso de caracteres especiais nos valores. Assim, se, por exemplo, o valor for uma frase ou o nome completo de uma pessoa, como “Fulano de Tal”, essa sequência de caracteres não pode ser enviada diretamente, nem como parte do caminho da URI nem como um parâmetro de busca, pois possui dois espaços, e eles não podem fazer parte da URI, devendo ser substituídos por “%20”. Outros caracteres especiais também devem ser substituídos por seus respectivos códigos de formatação usando "%cod".

Outra característica importante dos valores enviados ao web service, tanto com @PathParam quanto com @QueryParam, é que essas anotações podem ser utilizadas apenas com os seguintes tipos de dados:

  • Todos os tipos primitivos, exceto char;
  • Todas as classes wrapper para tipos primitivos, exceto Character;
  • Qualquer classe que tenha um construtor que aceite uma única String como argumento;
  • Qualquer classe que tenha um método estático chamado valueOf que receba como argumento uma única String para realizar a sua inicialização;
  • List, Set ou SortedSet, nos quais T corresponda aos critérios já listados nos marcadores anteriores.

Caso a anotação @DefaultValue() não tenha sido especificada para uma variável e o parâmetro não estiver presente na requisição, o valor atribuído será o valor padrão para tipos primitivos, uma coleção vazia quando for o caso ou nulo para outros tipos de objetos.

Por fim, além dos parâmetros de caminho e de busca, também estão disponíveis os seguintes tipos de parâmetros: Form, Cookie, Header e Matrix, que não serão tratados neste artigo. Todos eles obedecem às mesmas regras citadas.

Enviando parâmetros no corpo de uma requisição

O leitor mais atento deve ter notado que os exemplos apresentados até o momento recebem seus parâmetros através da URI de acesso ao web service. No entanto, é válido ressaltar que essa não é a única maneira de enviar dados utilizando o protocolo HTTP. Para entender melhor como esse processo de envio de dados acontece, é preciso conhecer um pouco do funcionamento desse protocolo, no qual um cliente envia mensagens no formato de uma requisição HTTP (Figura 7) e o servidor responde com outra no formato de uma resposta HTTP (Figura 8). Em uma requisição HTTP, as mensagens possuem as seguintes partes:

  1. O Verbo identifica qual é o tipo de requisição que está sendo enviada, podendo ser GET, PUT, etc.;
  2. A URI (Uniform Resource Identifier) especifica o endereço do recurso que se deseja acessar no servidor;
  3. Versão HTTP indica qual a versão do protocolo;
  4. O cabeçalho da requisição especifica os metadados da requisição no formato de pares chave-valor, por exemplo: tipo de cliente ou navegador, formatos suportados pelo cliente, formato do corpo da mensagem, configurações de cache, etc.
  5. O corpo da requisição é o conteúdo da mensagem ou a representação de um recurso.

Já as mensagens de resposta HTTP possuem as seguintes partes:

  1. O código de resposta indica o estado do servidor para o recurso solicitado, por exemplo: 404 significa recurso não encontrado e 200 significa sucesso;
  2. Versão HTTP indica qual a versão do protocolo;
  3. O cabeçalho da resposta especifica os metadados a respeito da mensagem de resposta no formato de pares chave-valor, por exemplo: tamanho do conteúdo, tipo do conteúdo, data, tipo do servidor, etc.;
  4. Ocorpo da requisição é o conteúdo da mensagem de resposta ou a representação do recurso solicitado.

Formato de uma requisição HTTP
Figura 7. Formato de uma requisição HTTP.
Formato de uma resposta HTTP
Figura 8. Formato de uma resposta HTTP.

Note que todos os exemplos apresentados até o momento não utilizaram o campo da mensagem HTTP, que corresponde ao conteúdo, o corpo da requisição. Utilizando esse espaço é possível informar que os dados necessários para completar uma requisição do web service sejam transferidos no corpo da mensagem de requisição do serviço e não na URI. Como exemplo, as requisições tratadas tanto na Listagem 5 quanto na Listagem 6 podem ser modificadas para receber os seus parâmetros dessa forma. A maneira de especificar isso no código é utilizando a anotação @Consumes(), passando como argumento o tipo de dado esperado. Como nos exemplos anteriores são esperadas sequências de caracteres sem nenhuma formatação especifica, o tipo de dado a ser utilizado é o MediaType.TEXT_PLAIN.

O código correspondente às requisições PUT e POST modificadas está na Listagem 8, na qual pode-se perceber que os caminhos para os recursos continuam os mesmos, mas sem a especificação dos parâmetros na URI como nos exemplos anteriores, modificando-se apenas os nomes dos métodos Java para que não ocorra um erro de compilação por existirem dois métodos com a mesma assinatura. Nesses casos as requisições são diferenciadas umas das outras pelo número de elementos na URI, ou seja, se existir algum valor especificado após o caminho /enviar na URI, o método que recebe os parâmetros pela URI será invocado, caso contrário, o método que recebe o parâmetro pelo corpo da mensagem será chamado.

Listagem 8. Enviando dados ao web service através do corpo da requisição HTTP.

public class WebServiceOla
  {
  // código repetido omitido...
   
         @PUT
         @Path("/enviar")
         @Produces(MediaType.TEXT_PLAIN)
         // A anotação @Consumes informa o tipo de dado consumido/recebido pelo método
         @Consumes(MediaType.TEXT_PLAIN)
         public String criaRegistroCorpo(String registro)
         {
                // Aqui deve ser incluído o código para criar o registro solicitado.
               return "Registro: \''" + registro + "\'' criado com sucesso!";
     }
   
         @POST
         @Path("enviar")
         @Produces(MediaType.TEXT_PLAIN)
         // A anotação @Consumes informa o tipo de dado consumido/recebido pelo método
         @Consumes(MediaType.TEXT_PLAIN)
         public String atualizaRegistroCorpo(String registro)
         {
               // Aqui deve ser incluído o código para atualizar o registro solicitado.
               return "Registro: \''" + registro + "\'' atualizado com sucesso!";
         }
  }

No exemplo da Listagem 8, o tipo de dado enviado ao servidor foi um conjunto de caracteres sem nenhuma formatação, o que, para esse caso simples ou quando o dado a ser enviado é formado por uma única sequência de caracteres, funciona bem. Em aplicações reais, no entanto, é necessário utilizar uma estrutura padronizada de caracteres para representar os dados.

Para esses casos, como já mencionado, um dos padrões mais utilizados é o XML, que permite que uma aplicação defina a estrutura dos dados que devem ser transmitidos. Além disso, existem APIs para tratar arquivos XML, o que facilita muito a adoção dessa opção. O mesmo pode ser dito do JSON, que também pode ser empregado para formatar os dados no corpo das mensagens HTTP.

De acordo com a arquitetura REST, os web services não devem manter informações a respeito do estado do cliente no servidor, ou seja, é responsabilidade da aplicação cliente enviar o seu contexto ao servidor, que pode ou não o armazenar para processar futuras requisições do cliente.

Nos exemplos estudados, os métodos do web service não armazenam qualquer informação a respeito do cliente que realiza a requisição. Sendo assim, se a URI localhost:8080/servico/enviar/teste for enviada utilizando um navegador web, um cliente Java ou uma aplicação como a Advanced Rest Client, a resposta será exatamente a mesma, sem nenhuma distinção nos dados que serão armazenados no arquivo ou banco de dados correspondente à aplicação, cujos recursos estão disponíveis aos clientes através do web service. A isso se dá o nome de “sem monitoração de estado” ou stateless, em inglês.

Os Big Web Services, ou web service SOAP, diferentemente dos web services RESTful, realizam o monitoramento de estado das solicitações, ou seja, mantêm, entre outras informações, um histórico das requisições já enviadas por cada cliente.

Levando isso em consideração, pode-se elencar algumas vantagens para web services sem monitoramento de estado:

  • Cada requisição pode ser tratada independentemente;
  • O projeto da aplicação é simplificado já que não é necessário manter as interações anteriores do cliente;
  • O protocolo HTTP em si é sem monitoramento de estado. Portanto, web services RESTful trabalham perfeitamente com o HTTP.

Por outro lado, também existem desvantagens ao utilizar web services sem monitoramento de estado:

  • Cada requisição necessita de informações extras, que precisam ser interpretadas para determinar o estado do cliente, caso as interações do cliente devam ser levadas em consideração;
  • Informações a respeito da seção de um usuário devem ser mantidas no cliente, e a cada nova requisição devem ser enviadas ao web service para validação do nível de acesso correspondente, quando for o caso.

O uso de web services como parte de aplicações, sejam elas corporativas ou não, já se tornou um padrão no desenvolvimento de software. A necessidade de conhecer os conceitos e características das tecnologias empregadas nesse tipo de sistema, portanto, é uma necessidade para os desenvolvedores.

Os exemplos abordados durante o artigo apresentam algumas das características fundamentais para a criação de web services RESTful, no entanto esses exemplos não estão vinculados a uma aplicação e, portanto, não definem um serviço específico, como manter um cadastro de pessoas ou permitir o acesso a um conjunto de métodos específicos para processar um certo tipo de dado. Cabe a cada analista ou desenvolvedor, a partir dos conhecimentos aqui abordados, identificar situações nas quais os sistemas em que trabalham possam se beneficiar do uso dessa tecnologia, como: a geração de páginas de conteúdo dinâmico a partir de requisições de serviço informando alguns parâmetros de busca.

É importante ressaltar que uma das grandes vantagens do uso de web services é fornecer uma forma de acesso segura a recursos, disponíveis em uma máquina ou em uma rede, que não devem estar expostos na internet, como no caso de servidores de bancos de dados. Nesses casos é possível escrever um conjunto de web services que publique um conjunto de ferramentas de acesso à base de dados para possibilitar que usuários consigam realizar consultas ou até mesmo algumas alterações, sem correr o risco de acessos indevidos. Isso ocorre porque todas as interações com a base de dados serão feitas através do web service, que disponibiliza uma interface padronizada sem a possibilidade de que algum tipo de operação não autorizada seja realizada, visto que o acesso à base de dados, ou a qualquer recurso a ser protegido, estará nele codificado, evitando assim que requisições com erros ou com objetivos escusos causem danos aos dados.

Para exemplificar as questões de segurança mencionadas, pode-se pensar em uma indústria cujos equipamentos podem ser controlados e configurados remotamente, caso os canais de controle estejam acessíveis diretamente pela internet. Neste caso, seria possível, através de tentativa e erro, descobrir as senhas e alterar as configurações, causando desde problemas na produção a defeitos nos equipamentos. Ao utilizar um conjunto de web services, para realizar o acesso a esses equipamentos, apenas as requisições implementadas poderão ser utilizadas, além de ser viável identificar padrões de ataque nas requisições, evitando acessos indevidos.

Outra situação na qual o uso desse tipo de sistema pode trazer vantagens é na disponibilização de recursos computacionais exclusivos de determinada máquina para um público mais abrangente. Por exemplo, no caso de uma instituição que possua um supercomputador, alguns de seus sistemas podem ser disponibilizados para acesso externo através de web services, possibilitando a usuários que não se encontrem próximos à máquina acesso ao poder computacional dessa para resolver problemas.

Conteúdos Recentes:

  • Como criar autocomplete em Delphi:
    Neste exemplo você aprenderá a criar um autocomplete em Delphi. Este é um recurso que possibilita filtrarmos uma lista com base em um texto informado. Aprenderemos a criar esse efeito implementando o mesmo em um cadastro de cliente, localizando uma determinada cidade com base em sua UF.
  • Primeiros passos com a jQuery:
    Aprenda neste curso front-end como criar botões com a biblioteca jQuery.
  • .NET na prática:
    Neste Guia de Consulta você encontrará conteúdos que abordam na prática o desenvolvimento de aplicações em .NET utilizando seus variados frameworks, como ASP.NET MVC, Web API e Entity Framework.

Links Úteis

Saiba mais sobre RESTful;)

  • O que é RESTful:
    Este curso possui por objetivo apresentar o que é o REST e qual a diferença entre REST e RESTful.
  • Criando um serviço RESTful com Java:
    Este curso possui o objetivo de explorar as facetas do paradigma de programação RESTful dentro do universo do Java.
  • Construindo uma API RESTful em Java:
    Este artigo apresenta o estilo REST de construção de web services, bem como as melhores práticas comumente adotadas na criação de uma RESTful API.
  • REST e Java:
    Devido a sua simplicidade, os Web Services RESTful têm se tornado cada vez mais populares. Neste guia você encontrará os conteúdos que precisa para dominar esse modelo que permite a construção de serviços menores a APIs completas.