Filtros REST em Rails e Java

18 de março de 2010

Para aqueles que gostariam de ver somente o conteúdo relativo as notícias de gerenciamento ágil, assinem o feed da categoria agile.

Para quem gostaria de assinar o feed completo, utilize o feed principal.

Muitas aplicações web possuem páginas de relatórios com campos para filtragem. O exemplo mais famoso é o caso onde o usuário pode configurar a data inicial e final para filtragem de dados.

FIltragem de dados

Mas o que acontece quando o usuário clica em qualquer link desse relatório, ou de relatórios consecutivos que aparecem após o mesmo? A data se perde. Em situações genéricas, o filtro se perde.

Vou exemplificar três maneiras de implementar tal funcionalidade.

Armazenar na sessão

É muito comum ver aplicações onde na primeira tela somos responsáveis por escolher, por exemplo, com qual unidade, centro de custo ou contrato desejamos trabalhar e, a partir de então, com tal valor armazenado na sessão no lado do servidor, temos acesso a URIs como http://www.projeto.com.br/clientes que retornaria a lista de clientes de uma unidade.

O que acontece se desejo trabalhar com clientes de duas unidades ao mesmo tempo, em abas distintas? Tenho que mudar de unidade a cada clique que executo com clientes de unidades diferentes.

Além disso, caches públicos como proxies entre o servidor e o cliente não terão o mesmo ganho de desempenho com URIs identificadoras de recursos reais.

O load-balancing também se torna custoso pois a sessão fica presa a uma máquina ou deve ser replicada em determinados momentos.

Tudo isso acontece pois sua aplicação é stateful, quebrando uma das regras da arquitetura REST.

O escopo flash é uma solução que cai nessa categoria.

Parâmetros do request

Outra solução é quando as características do filtro são passadas por parâmetros em uma URI do acessada através de GET.

parametros get

Nesse caso, podemos sobrescrever o método utilizado para definição de links para sempre adicionar os parâmetros de filtagem (url-rewriting):


  # remembers the starting and end date on all links
  def url_for(options = {})
    options[:start_date] = params[:start_date]
    options[:end_date] = params[:end_date]
    super(options)
  end

  public String urlFor(Class resource, String method) {
     return "/" + resource.getName() + "&start_date=" + params("start_date") + ...;
  }

Note que em ambos os casos é possível criar um componente que decide se o parâmetro de filtragem deve ou não ser adicionado.

Com um único método (monkey patch no Rails ou definição de tag no Java) somos capazes de resolver o problema em todos os links de um sistema.

Note que com essa abordagem, não existem os problemas de sessão apresentados anteriormente.

Armazenar um cookie no client

Aqui, como na solução baseada em sessões, existe o problema do trabalho em unidades distintas em diversas abas.

Uma vez que o cookie registrou informações relativas ao estado do cliente no processo definido no servidor, as próximas requisições irão levar em consideração tal informação, em todas as abas.

Novamente perdemos escalabilidade e, se usado em conjunto com sessões, temos um fator a mais negativo no load balancing.

REST

A segunda solução é a única que se aproxima mais de uma arquitetura REST: o servidor não mantém estado e a URI identifica um recurso, onde, por exemplo, open search pode ser utilizado para o sistema de filtragem.

O segredo está em deixar o cliente através de recursos identificados por URIs, ser guiado pelo servidor, e nenhum dos dois armazenem informações relativas ao estado atual de um processo. Os recursos e seus links ditam o processo (HATEOAS).

Note que de todas as soluções, ela foi a mais simples de trabalhar e com mais vantagens.

Além disso, não foram usados cookies que quebram a transparência para layers intermediários.

Fuja de cookies e de sessões, viva uma vida mais rest.

Anúncios

4 Respostas to “Filtros REST em Rails e Java”

  1. Danilo Sato Says:

    Muito bom o post Guilherme,

    Tem uma outra solução que pode ser considerada REST também: usar o padrão POST-redirect-GET.

    Ao invés de mandar os parâmetros como query string (que tem um limite no tamanho aceito), o cliente manda os parâmetros como parte do corpo de um POST, e o servidor é responsável por criar um recurso que representa aquele relatório específico, respondendo com um redirect (302 ou 303) com Location apontando pra uma URI transparente que identifica o relatório.

    Essa solução tem vantagens e desvantagens também. Seus argumentos de cache valem e essa URI passa a representar para sempre essa instância única do relatório (isso pode ou não fazer sentido). Por outro lado, o servidor precisa armazenar esse estado, mas não relativo aquela sessão ou cliente. Talvez o exemplo de um relatório não seja um bom cenário pra usar POST-redirect-GET, mas existem outros usos onde esse padrão se torna interessante. Como sempre, depende do contexto da aplicação que se está desenvolvendo.

    Ah, e em Rails, ao invés de fazer monkey patch no url_for(), eu usaria o default_url_options() que é um hook justamente pra fazer esse tipo de coisa 🙂

    • Guilherme Silveira Says:

      Opa Danilo, tudo bom?

      Adiantou parcialmente meu próximo post, que estava ligado com a criação de recursos ao invés da execução parametrizada… muito parecido com a transação x recursos: http://guilhermesilveira.wordpress.com/2009/12/17/transactions-do-not-exist-in-a-restfulie-world/

      Acho que não só em “transações”, como nos relatórios ou em outras atividades do dia a dia nosso da web podemos traduzir para criação de recursos mesmo – caso contrário não defenderíamos abordar rest – você está certo…

      Acho a solução do Created é valida pra relatórios, principalmente quando o processamento pode ser assincrono (202) ou sincrono (201). Algum motivo para preferir os 300?

      Se o mesmo for uma URI que não precisa armazenar estado no server (i.e. o resultado da busca por XPTO ser http://server/busca/xpto) – elimina a necessidade do post – e tambem permite cacheamento bem educadinho, fora os problemas classicos de URI.

      Mas mesmo que armazene, tem exemplos de aplicacoes webs magicas que obtem resultados fantasticos com isso (o proximo post!)

      Valeu pela sugestão do default_url_options() que vai ser ainda mais educado

      Abraço!

      Guilherme

      • Danilo Sato Says:

        Jóia. Foi mal estragar a surpresa 🙂

        Você tem razão com responder 2XX no contexto de REST quando é uma aplicação conversando com a outra. Eu tinha dito 3XX pq nem todos os browsers entendem o 201 como algo que ele precisa buscar.

        Eu sei que muita gente que defende REST não gosta do comportamento dos browsers em geral mas é um dos jeitos que eu acho mais fácil pra começar a aprender REST (inclusive hypermedia): imagine que o outro sistema é um usuário e vc está provendo um website.. o que ele faria? Agora escreve um programa que faz o que o usuário faria e joga fora o CSS 🙂

        Outro exemplo (que faria mais sentido): Você tem um formulário que é multi-páginas pro usuário preencher. Com POST-redirect-GET no browser, vc não tem mais problema de re-submeter o mesmo formulário pois agora ele tem uma URI única praquele formulário, e o usuário pode dar GET (refresh no browser) quantas vezes quiser.

    • Suffian Says:

      isnt it weird how they’re are some fake ass sureno that only talk shit on the net then in the real world in Northern Cali which they think their tankig over which there not then they wont be talking shit when their Nortenos around they’ll be quiet and then when a Norteno figures out that hes a scrap then their excuse is I dont gangbang or any of that shit


Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: