Desvendando Serviços Web RESTful – Parte 2

Versão 1.0

06.08.2014


Esta segunda parte, mais prática, mostra o RESTful em termos do protocolo HTTP. Os exemplos usarão como base o serviço do Foursquare.

Caso tenha chegado até aqui buscando um tutorial da API do Foursquare, esse artigo também servirá para tal. Será explicado detalhadamente, por meio de exemplos, os métodos da API de busca, autenticação e checkin.

Como visto na Parte 1, o RESTful é todo baseado em padrões abertos (XML, JSON, etc) e no protocolo HTTP. Ele é um modelo semelhante ao da Web sendo que ao invés de receber páginas HTML, o cliente consome informações oferecidas pelo serviço. Essas informações são representadas através do conceito de recursos.

O recurso é qualquer coisa que pode ser ofertado para o cliente. Eles são acessados usando uma URI juntamente com determinado comando. Os comandos são os métodos do próprio protocolo HTTP que possibilita diferentes ações como criar, apagar, atualizar ou recuperar determinado recurso. Dessa forma, um serviço oferta recursos através de comandos que são operados sobre URI’s.

Normalmente um serviço RESTful é descrito por meio de métodos. Cada método do serviço é composto por uma URI e o respectivo método do protocolo HTTP.

As URI’s são nada mais do que uma URL que se segue depois do domínio do serviço. Caso o método precise de informações extras, os parâmetros do HTTP são usados.

Por exemplo, determinado recurso que segue o padrão CRUD (criar, atualizar, deletar e ler) pode ser estruturado usando os seguintes métodos e URI’s:

Método do Serviço Método HTTP URI
Recuperar todos os livros GET /books
Recuperar livro GET /book/{id}
Atualizar livro POST /books/{id}
Atualizar livro PUT /books/{id}
Apagar livro DELETE /books/{id}

Lembrando que essa é uma das formas de organizar o acesso a um recurso, que segue um padrão para as URI’s e uma correlação semântica com os métodos do HTTP.

No serviço do Foursquare, um dos principais recursos ofertados é o venue.

Ele representa o conceito de lugares ao redor do mundo que podem ser visitados pelas pessoas. Utilizando a API podemos, por exemplo, adicionar novos lugares, curtir, buscar lugares próximos, como também fazer checkin em um lugar.

Para cada uma dessas funcionalidades são definidos métodos HTTP, URI’s e parâmetros. A figura abaixo resume os métodos para criar, buscar e fazer checkin em lugares. Os métodos para buscar e checkin serão explicados mais adiante.

Métodos do serviço do Foursquare

Alguns dos métodos do serviço do Foursquare

Para enchegarmos como o HTTP é usado em cada uma dessa requisições e respostas vou utilizar o plugin do Chrome REST Console por ele ser simples e de rápida utilização. Apesar de ser simples, ele possui todos os recursos para testar um serviço RESTFul como envio de dados em XML, JSON, manipulação do cabeçalho, autenticação, etc.

Outro software que gosto bastante é o SoapUI que pode ser utilizado para testar tanto serviços REST como outros tipos de serviços. Sua interface é bastante poderosa possibilitando salvar um projeto ao contrário do REST Console.

Neste artigo irei utilizar como base a API do Foursquare para exemplificar as requisições a um serviço RESTFul. Como todas as API’s existentes, uma camada de segurança é usada para controlar o acesso e prover autenticação. Os passos a seguir descrevem como obter acesso a API e em seguida os métodos de busca de lugares, checkin e adição de lugares serão apresentados.

Ao contrário de outras API’s, o acesso aos métodos pode ser feito utilizando autenticação OAuth2 ou um par de chaves associadas a uma aplicação registrada. Os métodos na API que criam recursos utilizam OAuth2, já aqueles para listar ou de busca precisam apenas dos pares de chaves. Todos os dois tipos serão explicados aqui.

O acesso começa criando uma aplicação. Para comecar crie uma conta no foursquare e depois va até o link e clique em “Create a new APP” para registrar uma nova aplicação. Digite o nome da sua aplicação e na parte “Web Addresses” informe para o campo “Welcome URL” a URL http://localhost:3000/welcome e para o campo “Redirect URI” digite o endereço http://localhost:3000/redirect_url. O campo redirect uri é importante, pois será a URL necessária para podermos receber o token de acesso quando usando autenticação OAuth2.

Ao criar a aplicação recebemos duas chaves o Client ID e o Client Secret. Através dessas duas chaves já podemos utilizar o método para buscar lugares. Ele possui como URI /venues/explore, o método GET e uma serie de parâmetros para direcionar a busca. Consulte a documentação para mais detalhes.

Buscaremos lugares cujos nomes contenham determinada palavra-chave (parâmetro query) e estão localizados dentro de determinada cidade (parâmetro near). Por exemplo, a URI final para buscar lugares que vendem açai fica:

https://api.foursquare.com/v2/venues/explore?
near=JoaoPessoa&query=Acai&client_id=SEU_CLIENT_ID&
client_secret=SEU_CLIENT_SECRET&v=20131016

A URL do serviço é https://api.foursquare.com/v2 e precede a URI do recurso. Observe que precisamos passar como parâmetros da requisição o client id (client_id), o client secret (client_secret) da aplicação que acabamos de criar e a versão da api (v).

Para executar o método no Chrome abra o plugin Rest Console. Em seguida vá até a seção Target e no campo Request URI coloque a URI anterior. No campo Content-Type digite application/json, no campo Request Method escolha GET e por fim clique no botão Send para enviar a requisição. Ao terminar a requisição a resposta é recebida e exibida na seção Response.

O campo content-type é um campo da requisição que indica qual o tipo de conteúdo a ser recebido. Por exemplo, no caso de receber XML passariamos application/xml no content-type.

Usando o Rest Console

Usando o Rest Console

O método explore retorna uma lista de lugares (venue) dentro do objeto json response. O código abaixo exibe o JSON da resposta simplificado com apenas dois dos vinte lugares retornados na resposta.

{
"meta": {
    "code": 200
},
"response": {
    ...
    "venue": {
        "id": "4c6b0783e503c928332947b3",
        "name": "Manaçaí",
        "contact": {
            "phone": "+558332469207",
            "formattedPhone": "+55 83 3246-9207",
            "twitter": "manacaioficial"
        },
        "location": {
            "address": "Av. Euzely Fabrício de Souza, 681",
            "crossStreet": "Av. Sapé",
            "lat": -7.103021972897571,
            "lng": -34.83786106109619,
            "postalCode": "58038-382",
            "cc": "BR",
            "city": "João Pessoa",
            "state": "PB",
            "country": "Brazil",
            "formattedAddress": ["Av. Euzely Fabrício de Souza, 681 (Av. Sapé)", "João Pessoa, PB", "58038-382", "Brazil"]
        },
        ...
        "hereNow": {
            "count": 1,
            "summary": "One person here",
            "groups": [{
                "type": "others",
                "name": "Other people here",
                "count": 1,
                "items": []
            }]
        }
    },
    "venue": {
        "id": "4f85ec60e4b048403d30bb67",
        "name": "Jampaçai",
        "contact": {
            "phone": "+558335784606",
            "formattedPhone": "+55 83 3578-4606"
        },
        "location": {
            "address": "R. Fernando Luiz Henrique dos Santos, 616, Lj. 9",
            "lat": -7.091750909473074,
            "lng": -34.83541126461676,
            "postalCode": "58038-000",
            "cc": "BR",
            "city": "João Pessoa",
            "state": "PB",
            "country": "Brazil",
            "formattedAddress": ["R. Fernando Luiz Henrique dos Santos, 616, Lj. 9", "João Pessoa, PB", "58038-000", "Brazil"]
        },
        ...
        "hereNow": {
            "count": 0,
            "summary": "0 people here",
            "groups": []
        }
    }
}

Continuando com o uso do serviço, o próximo método é o de fazer checkin em determinado lugar. No caso desse método precisaremos usar o esquema de autenticação OAuth2 do foursquare.

Ele consiste basicamente em passar como parâmetro de cada requisição um token de acesso. Para obter o token de acesso acesse a seguinte URL no seu navegador:

https://foursquare.com/oauth2/authenticate?
client_id=SEU_CLIENTE_ID&response_type=token&
redirect_uri=http://localhost:3000/redirect_url

O client_id é o cliente id da aplicação, o redirect_uri é a URL de redirecionamento para receber o token de acesso. Ele deve ser necessáriamente o mesmo valor especificado no campo “Redirect URI” quando criamos a aplicação. Caso seja diferente ocorrerá o seguinte erro “Cause of error: Callback uri is not valid for this consumer”.

Por último temos o response_type que é o parâmetro indicando que queremos obter o token de acesso. Ao acessar o link acima recebemos outro link no navegador que contém o token de acesso. Esse link será como:

http://localhost:3000/redirect_url#access_token=SEU_TOKEN_DE_ACESSO

Nesse caso, no sucesso da autenticação o browser está sendo redirecionado para a URL de redirecionamento que especificamos e passando nosso token através do parâmetro access_token. Agora com o valor do parâmetro access_token podemos usar qualquer método da API que requer autenticação.

O checkin num lugar é feito com a URI /checkins/add, usando o método POST do HTTP. Ele possui como parâmetro obrigatório o id do lugar para checkin.

Para fazer um checkin, usando o plugin Rest Console, no campo Request Method mude para método POST e no campo Request URI entre com a seguinte URI:

https://api.foursquare.com/v2/checkins/add?
oauth_token=SEU_TOKEN_DE_ACESSO&
venueId=4f85ec60e4b048403d30bb67&
shout=Entrei aqui sem ser pelo aplicativo do foursquare. Não é demais?&
broadcast=facebook&v=20131016

O parâmetro oauth_token é o token de acesso que conseguimos na autenticação. Como estamos usando o token não precisamos mais passar o client_id. O parâmetro venueId especifica o id local do checkin e pode ser conseguido pela busca de lugar através do campo id da entidade venue. O parâmetro shout especifica uma mensagem de checkin e o broadcast indica que queremos compartilhar no facebook.

Advertisements

Desvendando Serviços Web RESTful – Parte 1

Versão 1.0

23.06.2014


Este é o primeiro artigo de uma série de artigos sobre serviços web RESTful. Este começa pelos principais conceitos dos serviços RESTful e alguns aspectos envolvendo o seu projeto. É apresentado o emprego do padrão Data Transfer Object (DTO) no projeto, bem como estratégias para diminuir o esforço extra advindo no uso desse padrão. A parte 2 é mais prática e apresenta o serviço RESTful do ponto de vista do protocolo HTTP.

As famosas IDE’s Java (Eclipse, Netbeans) facilitam o desenvolvimento e abstraem todo o conhecimento da dinâmica por trás do desenvolvimento do serviço. O deploy de um serviço simples pode ser feito em questão de minutos. Apesar dessa mágica, é importante dominar os conceitos básicos dos serviços e conhecer o que realmente ocorre por detrás dos panos. Principalmente pelo fato que quando sua aplicação ou serviço não está se comportando de maneira adequada, você precisa verificar se aquela requisição foi enviada como esperado ou entender como foi a resposta recebida.

Um serviço web RESTful trata-se de um modelo para integração de sistemas que tem como base o protocolo HTTP e padrões abertos como o XML e JSON. É um modelo semelhante ao da Web (cliente servidor), a diferença é que ao invés de se ter requisições para código HTML (páginas), o cliente consume informações (recursos) oferecidos pelo serviço em termos de XML/JSON. O cliente aqui pode ser uma aplicação para celular ou uma aplicação web desenvolvida em qualquer tipo de plataforma.

O serviço web provê um conjunto de informações e responsabilidades bem definidas, entretanto elas somente fazem sentido quando consumidas (utilizadas) pelos clientes. O consumo inicia-se disparando a execução de métodos no serviço com o intuito de receber informações de interesse para a aplicação. Todo o processo é comandado pelo cliente que inicia e dá um significado aos dados recebidos.

O RESTful é todo baseado nas tecnologias web e no protocolo HTTP. Os recursos que queremos usar são identificados unicamente através de URI’s e os métodos do protocolo HTTP são utilizados para operar sobre determinado recurso. Por exemplo, o POST é usado para criar um novo recurso; o GET para lê as informações atuais do recurso; o PUT para atualizar um recurso; e o DELETE para deletar um recurso.

A URI é nada mais do que um hiperlink que nomalmente vem após o domínio do serviço. Ele é organizado de modo a identificar unicamente todos os recursos ofertados pelo serviço. Por exemplo, ao usar a API do Google Places, se quisermos ter acesso aos lugares próximos da gente (operação GET), a URI é /maps/api/place/nearbysearch. Outras URI’s são /maps/api/place/textsearch e /maps/api/place/radarsearch que identificam outros tipos de buscas.

O principal fator para interoperabilidade dos serviços web é que os dados são trocados utilizando padrões abertos como o XML e JSON. Do lado do cliente, ao recuperar informações dos recursos (GET), os dados recebidos pelo cliente estão num formato inteligível. E da mesma forma quando queremos criar novos recursos (POST), os dados são enviados no formato que o serviço também entende. Na parte 2 iremos exemplificar esses e outros casos no consumo de um serviço web real.

Do ponto de vista do projeto do serviço, o desenvolvedor representa as mensagens XML/JSON a partir dos objetos do domínio (por exemplo, clientes, produtos, etc.). Para cada requisição que chega os dados JSON/XML são transformados em objetos, em seguida um processamento é realizado e o serviço devolve uma resposta para o cliente. No lado do cliente, o cliente transforma o XML/JSON em objetos que passam a ser utilizados na aplicação. A figura abaixo ilustra esse cenário que ocorre numa típica requisição POST, onde o cliente envia e recebe os dados em XML/JSON.

Visão Geral das etapas de serialização/deserialização numa requisição

Visão Geral das etapas de serialização/deserialização numa requisição

Esse é um processo de serialização e deserialização feito tanto no cliente como no servidor e que utiliza a rede como meio para transportar os dados. Diversos frameworks como JAXB, XStream, GSON e Jackson, podem ajudar nessa tarefa de mapeamento de objetos para JSON/XML. O desenvolvedor precisa apenas anotar as classes (seus atributos e métodos) que o framework transforma os objetos do domínio em XML/JSON como também em recupera-o de volta. Dessa forma, os desenvolvedores trabalham apenas no nível dos objetos e ficam livres da tarefa ardua de usar API’s especificas para gerar e fazer o parser de XML/JSON.

O grande problema em usar os próprios objetos da camada de domínio para representar as estruturas de requisição ou resposta é torná-los fortemente acoplados. Essa dependencia faz com que qualquer alteração feita no modelo de objeto repercuta nas respostas enviadas para os clientes, o que implica em mudanças no lado do cliente. Do mesmo modo, uma mudança na estrutura de requisição ou resposta pode exigir que o modelo de domínio seja alterado.

Para resolver isso, o padrão Data Transfer Object (DTO) é empregado para representar em novas classes as requisições e respostas, bem como a lógica para serialização e deserialização. Com o DTO é criado uma camada responsável apenas pela manipulação das mensagens. Dessa forma, tanto a manipulação das estruturas de requisições e respostas quanto o modelo de domínio podem variar de forma independente.

O DTO são classes que representam apenas os dados das mensagens e não possuem regras de negócio. Originalmente, sua motivação foi reduzir o número de chamadas a uma interface remota [2], quando os dados necessários estavam espalhados no grafo de objetos do domínio. Apesar disso, ele acabou sendo usado no cenário de serviços web para desacoplar a manipulação das mensagens das entidades do domínio.

Outra vantagem do DTO é o seu reuso no lado do cliente. Normalmente essa tarefa é feita reusando as classes do próprio domínio do serviço ou então criando novas classes no lado do cliente. Porém, reusar o domínio do serviço causa forte acoplamento da aplicação com o domínio e muitas vezes esse reuso não é possível devido a como ele foi projetado. Por exemplo, o reuso de um domínio anotado com JPA numa aplicação Android, apesar de ser possível, deve ser gerenciado.

A figura abaixo resume a estrutura geral de um serviço web com o uso de DTO. Os Domain Objects são os objetos do domínio e descrevem a lógica do serviço. Os DTO Objects representam as requisições e respostas e podem ser usados tanto no lado do cliente como no lado do servidor. Normalmente ele é criado como um módulo separado que é reusado no cliente. Com o uso do DTO é preciso mapear os objetos do domínio nos objetos DTO. Afinal o serviço é implementado em termos destes.

Estrutura do serviço com Data Transfer Objects (DTO)

Esse esforço extra pode ser considerado uma desvantagem da abordagem DTO, pois demanda trabalho para criar os objetos DTO a partir dos objetos do domínio e vice e versa. Para facilitar essa tarefa, existem diversos frameworks que fazem esse trabalho automaticamente. Soluções como Dozer e Automapper podem ser usados nessa tarefa enfadonha. Em cenários mais simples, quando o objeto DTO é semelhante ao objeto do domínio, nenhuma configuração é necessária. O DTO é transformado em JSON/XML usando frameworks como JAXB, XStream, Jackson, etc.

DTO de forma geral auxilia na manutenção do código do serviço diminuindo o acoplamento entre a manipulação da mensagens e o domínio, além de promover reuso de código no lado do cliente. Apesar no esforço extra em manter novas classes, estrategias de mapeamento objeto-objeto facilitam o uso desse padrão.

Criar um serviço RESTful passa não só pelo dominio das ferramentas (API’s, frameworks e IDE’s) usadas para desenvolvê-lo. É necessário também saber o que acontece de fato quando uma requisição chega no servidor e como ocorre o uso do serviço pelo cliente (consumo do serviço). É essencial entender como são as requisições e as repostas durante a comunicação, além de dominar como o protocolo HTTP é usado pelo RESTful. A parte 2 desse artigo apresenta como o serviço RESTful utiliza o HTTP durante a comunicação.

Referências

Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services. Robert Daigneau. Addison-Wesley.

Artigo Martin Fowler Data Transfer Objects