Retorno dinamico (mime type) + vraptor

11 respostas
Nykolas_Lima

Gostaria de criar webservices rest com vraptor.

Queria fazer algo mais o menos como rails.
/clientes/1.json -> retorno json
/clientes/1 -> retorno html

Como eu posso fazer isso com vraptor?

11 Respostas

Lucas_Cavalcanti

O ideal é fazer isso via o header Accepts…

daí vc faria:

GET /clientes/1 Accepts: application/json
GET /clientes/1 Accepts: text/html

daí é só vc usar o result.use(Results.representation()).from(objeto).serialize(); que já funciona.

agora dá pra simular esse comportamento criando um filtro que modifica o request de acordo com a extensão… se quiser ajuda pra isso dá um toque :wink:

Nykolas_Lima

Lucas Cavalcanti:
O ideal é fazer isso via o header Accepts…

daí vc faria:

GET /clientes/1 Accepts: application/json
GET /clientes/1 Accepts: text/html

daí é só vc usar o result.use(Results.representation()).from(objeto).serialize(); que já funciona.

agora dá pra simular esse comportamento criando um filtro que modifica o request de acordo com a extensão… se quiser ajuda pra isso dá um toque ;)

Lucas,
O header Accepts seria configurado no client, certo?

Não entendi direito como fazer isso.

A minha situação é a seguinte, vou criar uma aplicação que terá 3 clientes: IPhone, Android e o Site.
Gostaria de escrever apenas 1 Controller para as 3 interfaces.
Para as interfaces mobile eu utilizaria o retorno json, como um webservice. Para a interface web seria o fluxo normal do vraptor, com forwards, redirects e etc.

Como seria a melhor maneira de fazer isto?

Lucas_Cavalcanti

se vc está usando algum http client para fazer a requisição, só pedir pra adicionar o header Accept do jeito que eu te falei

httpClient.addHeader("Accept", "application/json");

todo http client deveria ter como fazer isso, de algum jeito.

daí é só usar o representation() que ele vai fazer do jeito que vc quer.

Nykolas_Lima

Lucas Cavalcanti:
se vc está usando algum http client para fazer a requisição, só pedir pra adicionar o header Accept do jeito que eu te falei

httpClient.addHeader("Accept", "application/json");

todo http client deveria ter como fazer isso, de algum jeito.

daí é só usar o representation() que ele vai fazer do jeito que vc quer.


Lucas, fiquei em dúvida em uma coisa.

Vamos supor o seguinte fluxo:

if(json) {
//serializa o objeto e retorna o json
} else if(html) {
//forward pra outra action que irá listar os resultados
}

Como eu faria isso com este representation?

Lucas_Cavalcanti

não é só dar forward pra action de listagem? e nela fazer a lógica do representation()?

tenta fazer o seguinte:

public void metodo(....., @HeaderParam("Accept") String accept) {
    .....
    if ("application/json".equals(accept)) {
           ....
    } else {
           ;;;;
    }
}
Nykolas_Lima

Lucas Cavalcanti:
não é só dar forward pra action de listagem? e nela fazer a lógica do representation()?

tenta fazer o seguinte:

public void metodo(....., @HeaderParam("Accept") String accept) {
    .....
    if ("application/json".equals(accept)) {
           ....
    } else {
           ;;;;
    }
}

Lucas, vou tentar fazer conforme você esta falando com o @HeaderParam.

Você pode me explicar o que o código abaixo faz quando o retorno é para ser HTML?

result.use(Results.representation()).from(objeto).serialize();
Lucas_Cavalcanti

pro html é como se vc tivesse feito:

result.include(objeto);

e ele vai pra jsp padrão

Nykolas_Lima

Lucas Cavalcanti:
pro html é como se vc tivesse feito:

result.include(objeto);

e ele vai pra jsp padrão

Lucas, muito obrigado pela ajuda mas acho que vou seguir a opção de criar um filtro para tratar a extensão da url (ex: client/1.json)

Você havia dito que poderia ajudar nesta implementação, você já tem algo pronto sobre isso?

Lucas_Cavalcanti

registra esse filtro antes do filtro do vraptor:

public class ContentTypeFilter implements Filter {
   //init
   //destroy

   public void doFilter(req, res, chain) {
          
        chain.doFilter(new HttpServletRequestWrapper(req) {
              @Override
              public String getRequestURI() {
                   return super.getRequestURI().replaceFirst(".json$", "");
              }

              @Override
              public String getHeader(String name) {
                     if ("Accept".equalsIgnoreCase(name)) {
                           String header = super.getHeader(name);
                           if (header == null) {
                                 if (super.getRequestURI().endsWith(".json"))
                                       return "application/json";
                           }
                     }
                    return super.getHeader(name);
              }
         }, res);
   }

}

bom, com as devidas compilações corrigidas :wink: e se precisar de mais tipos, só adicionar nos ifs

Mr_Arthur

Aproveitando o tópico, bastante útil por sinal.

Qual o comportamento padrão do vraptor quando eu mando um header “Accept”?
Fiz uma requisição para uma controller com o header de valor “text/plain” e resultou nisso:

&lt;html&gt; &lt;head&gt; &lt;title&gt;Apache Tomcat/7.0.29 - Error report&lt;/title&gt; &lt;style&gt; &lt;!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--&gt; &lt;/style&gt; &lt;/head&gt; &lt;body&gt; &lt;h1&gt;HTTP Status 404 - /WEB-INF/jsp/pessoa/index.text/plain.jsp&lt;/h1&gt; &lt;HR size="1" noshade="noshade"&gt; <p> <b>type</b> Status report </p> <p> <b>message</b> <u>/WEB-INF/jsp/pessoa/index.text/plain.jsp</u> </p> <p> <b>description</b> <u>The requested resource (/WEB-INF/jsp/pessoa/index.text/plain.jsp) is not available.</u> </p> &lt;HR size="1" noshade="noshade"&gt; &lt;h3&gt;Apache Tomcat/7.0.29&lt;/h3&gt; &lt;/body&gt; &lt;/html&gt;

Quando mando “text/html” tudo ok. “application/json”, o mesmo erro a cima.

Valeu!

Lucas_Cavalcanti

qdo vc manda o accept e não é html, o VRaptor tenta chamar a jsp do content-type desse accept, daí vc teria que implementar esse jsp…

outra forma é colocar ao final do método do controller:

result.use(Results.representation()).from(umObjeto).serialize();

assim se o accept for html ele mostra a jsp, se for json ou xml ele serializa, se for text/plain vc vai ter que escrever um deserializer pra isso.

Criado 23 de julho de 2012
Ultima resposta 24 de out. de 2012
Respostas 11
Participantes 3