Usando XML de uma ActionBar para criar um menu Navigation Drawer

navigation drawer com xml

Nível: Intermediário

Versão 1.0

11.09.2014


Este artigo tem por objetivo apresentar uma forma mais rápida e fácil de se trabalhar com o Navigation Drawer do Android. Irei mostrar como esse menu, utilizado para navegação, pode ser construido utilizando apenas um arquivo XML idêntico ao da ActionBar.

A principal motivação de escrever esse artigo é de mostrar os problemas que passei usando o Nav Drawer e mostrar uma solução usando o que estamos acostumados no dia a dia com Android. O artigo foca apenas na criação da lista contendo os itens do menu e no tratamento de clique do item.

Não será explicado como implementar todo o Navigation Drawer, logo irei assumir que você já trabalhou com ele antes.

Navigation Drawer: Como normalmente é feito

O Navigation Drawer é um componente de interface do Android empregado como um opção para navegação.

Basicamente, é um painel contendo uma lista de ações que surge no canto esquerdo ou direito da tela. Esse tipo de menu é empregado quando a aplicação inclue muitos tipos de telas (ações) e assim pode facilitar a mudança de uma tela para outra estando em qualquer uma delas.

Sendo um alternativa ao menu da ActionBar, a API do Nav Drawer, da forma como é disponibilizada atualmente, não acompanhou o estilo de programação que temos quando definimos um menu na ActionBar.

Basicamente, um menu da ActionBar é criado inflando um arquivo XML no método onCreateOptionsMenu e tratando o clique do menu no método onOptionsItemSelected através do id do item do menu.

No Nav Drawer, ao contrário, não existe XML para definir o menu e o código de tratamento é feito usando a ordem de posicionamento dos itens no menu.

Como sabemos o menu consiste numa lista de itens criados a partir de um ListView. Basicamente a tarefa envolve criar um Adapter com a lista de itens do menu juntamente com um layout definindo um ícone e um texto. Além disso é preciso tratar o evento de clique no menu.

Este commit no meu github traz uma implementação normalmente utilizada. O adapter (do tipo ArrayAdapter) é criado no método onCreateView do fragmento que exibe o menu (linha 88 da classe NavigationDrawerFragment). O menu é criado com três itens, onde cada item exibe apenas um texto (layout simple_list_item_1 do próprio Android).

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        
        listView = (ListView) inflater.inflate(
                R.layout.fragment_navigation_drawer, container, false);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                selectItem(position);
            }
        });

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                getActionBar().getThemedContext(),
                android.R.layout.simple_list_item_1,
                android.R.id.text1,
                new String[]{
                        getString(R.string.title_section1),
                        getString(R.string.title_section2),
                        getString(R.string.title_section3),
                });

        listView.setAdapter(adapter);

        return listView;
    }

Como toda lista, o tratamento de clique do menu inicia-se registrando o listener do clique do menu usando o método setOnItemClickListener do ListView (linha 92). O listener dispara uma chamada ao método selectItem (linha 112), que por sua vez chama o método onNavigationDrawerItemSelected da atividade MenuActivity.

O método onNavigationDrawerItemSelected da atividade MenuActivity (linha 41 de MenuActivity) é responsável por fazer o tratamento do clique em si. Ele exibe cada tela (fragmento) a partir do clique. Observe que isto é feito relacionando cada posição da lista com sua respectiva tela.

Problemas existentes

Essa abordagem atual possui duas deficiências que impactam na produtividade e na manutenção do código:

  • Usar o posicionamento da lista para tratamento de clique do menu

Usando o posicionamento da lista temos sempre que saber qual a tela corresponde a posição na lista. Quando temos muitos itens de menu, isso torna-se passível a erros. pois teremos muitas associações para lembrar mentalmente.

Além disso, não favorece quando é preciso inserir uma nova ação no menu. Por exemplo, caso um novo item de menu seja adicionado a ordem do menu seria modificada e consequentemente a associação posição-tela teria que ser refeita novamente.

O código pode ser melhorado utilizando uma constante para identificar cada posição da lista, entretanto o segundo problema ainda persiste, pois quando a ordem do menu é alterada teremos que refazer o código de tratamento novamente.

  • Complexidade para modificar o menu

Quando é preciso modificar o menu, por exemplo, adicionando um novo item ou modificando a sua ordem, é preciso ir até o adapter na classe do fragmento e adicionar o código necessário.

Esse tipo de tarefa, apesar de ser simples, quando já feito anteriormente, adiciona mais complexidade ao projeto, irá despreender tempo e será mais uma possibilidade de introduzir erros. Vejamos como melhorar isso.

Abordagem utilizando XML

A ideia que vou mostrar aqui é como construir qualquer menu Navigation Drawer utilizando a mesma estrutura de programação empregada nos menus da ActionBar. Isto é, usando um XML para definir o menu e o tratamento do clique do menu usando um id do item do menu.

Definimos os três itens do nosso Nav Drawer usando o seguinte XML:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MenuActivity">

    <item
        android:id="@+id/menu_home"
        android:icon="@drawable/ic_home"
        android:title="@string/menu_home_title" />

    <item
        android:id="@+id/menu_find_people"
        android:icon="@drawable/ic_search"
        android:title="@string/menu_find_people_title"/>

    <item
        android:id="@+id/menu_photos"
        android:icon="@drawable/ic_photos"
        android:title="@string/menu_photos_title"/>

</menu>

Observe que o XML é o mesmo daquele quando definimos um menu para a ActionBar. Ele possui uma tag menu e para cada item do menu a tag item. Cada item é definido com seu respectivo id (menu_home, menu_find_people e menu_photos) juntamente com seu icone e título.

O próximo passo é modificar o Adapter do ListView. A única alteração a ser feita é tornar o adapter do tipo MenuItem, que é o tipo do item de menu. Dessa forma, o adapter passará a armazenar a lista de itens do menu. O trecho de código do nosso adapter fica:

List<MenuItem> menuItems = createMenu();
adapter = new ArrayAdapter<MenuItem>(
                getActionBar().getThemedContext(),
                android.R.layout.simple_list_item_1,
                android.R.id.text1,
                menuItems);
listView.setAdapter(adapter);

Observe que o adapter continua sendo um ArrayAdapter, mas agora esta ligado ao tipo MenuItem e a sua lista de objetos é a lista de items do menu. Essa lista pode ser obtida via código da seguinte forma:

private List<MenuItem> createMenu() {
    Menu menu = new MenuBuilder(getActivity());
    MenuInflater menuInflater = getActivity().getMenuInflater();
    menuInflater.inflate(R.menu.nav_menu, menu);
    List<MenuItem> menuItems = new ArrayList<MenuItem>();
    for(int i = 0;i < menu.size();i++) {
        MenuItem item = menu.getItem(i);
        menuItems.add(item);
    }
    return menuItems;
}

Com isso já temos o menu pronto com todos os itens do nosso XML. Caso queiramos um icone em cada item da lista do menu, basta implementar um adapter com um layout que contenha uma imagem e usar a propriedade icon do próprio MenuItem para especificar a imagem do item do menu.

A parte visual esta pronta, mas ele ainda não esta funcional. O próximo passo é reimplementar o método de tratamento de clique:

@Override
public void onNavigationDrawerItemSelected(MenuItem item) {
    …
    switch (item.getItemId()) {
        case R.id.menu_home:
            fragment = new HomeFragment();
            break;
        case R.id.menu_find_people:
            fragment = new FindPeopleFragment();
            break;
        case R.id.menu_photos:
            fragment = new PhotosFragment();
            break;
    }
    …
}

A mudança principal é diferenciar cada item do menu através do seu id. Para isso, estamos passando agora o próprio item do menu que foi clicado. O método getItemId do MenuItem e as constantes R.id.menu_home, R.id.menu_find_people e R.id.menu_photos são usados para saber qual o item foi clicado.

Observe que agora não mais usamos a posição da lista para identificar qual o item do menu foi clicado. Tudo é feito pelo id do menu que foi definido no XML.

Esta solução irá tornar mais fácil e rápida a utilização do Nav Drawer e também quando formos reusá-lo em outras aplicações. Com ela conseguimos:

Menos probabilidade a erros

A vantagem é que qualquer mudança no menu, seja para adicionar um novo item ou mudar a ordem atual dele, fica restrito ao XML. Podemos alterar icone, título, ordem dos itens sem ser preciso mexer no código do adapter nem no fragmento do menu.

Poupa tempo e complexidade na implementação do menu para a aplicação.

Como visto acima, implementar e manter um menu para uma aplicação demanda tempo. Sobretudo quando queremos reimplementar o mesmo menu para outras aplicações. Neste caso, ao reusar o menu em outro projeto teremos que mexer novamente no código.

Este tipo de tarefa, apesar de ser simples quando já feita anteriormente, adiciona mais complexidade ao projeto, irá despreender tempo e será mais uma possibilidade de introduzir erros.

Como o menu é definido em um xml, não é necessário intervir no código para adicionar novas ações. Basta modificar o xml e definir o tratamento de evento pelo ID do item clicado que teremos o Navigation Drawer funcional. Com isso estamos adicionado ao nosso projeto manutenabilidade, reusabilidade e diminuição da complexidade do código. Ou seja, em face as mudanças deixamos muito fácil a modificação do código existente.

Você pode ver as mudanças necessárias para implemetar esse tipo de menu com XML através do meu github. O código do Nav Drawer completo também pode ser obtido no link.

Advertisements

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.

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