Arquivo da categoria: REST

Conhecendo o Play Framework

Quem já experimentou frameworks como Django e Rails sabe bem que o desenvolvimento de aplicações web pode perfeitamente ser produtivo e até divertido. Isso estava fora da realidade do mundo Java antes do surgimento do Play Framework!.

O Play é um framework full stack, stateless, focado em produtividade, bastante parecido com Django e Rails. É construído sobre uma arquitetura assíncrona baseada em eventos, sendo muito simples de escalar. Possui suporte a módulos, gerenciamento de dependências e configuração baseada em arquivos properties. Não é necessário compilar e realizar deploy em um servidor de aplicações, o Play vem com um servidor embutido, e durante o desenvolvimento basta alterar o código, salvar e recarregar o browser. O próprio framework compila e recarrega a aplicação, como em linguagens interpretadas. E se houverem erros, eles serão exibidos no próprio browser, de forma intuitiva.

O Play vem com um conjunto de ferramentas em modo console para várias tarefas, como criar novos projetos, iniciar a aplicação com o servidor embutido, executar testes, configurar dependências, gerar um pacote WAR, etc, o que o torna bastante produtivo tanto para novos projetos quanto para dar manutenção em um projeto já existente. É possível desenvolver em Java ou Scala (sim, Scala!).

Vamos enumerar alguma das caracteristicas do framework:

  • Limpo, Rápido e Dinâmico
  • Produtivo, Poderoso e Divertido!
  • Puro Java (Permite a importação e uso de qualquer biblioteca Java)
  • Utiliza o sistema de template Groovy(Groovy trabalha de forma transparente com todos os objetos e bibliotecas Java existentes e compila diretamente para Java bytecode tanto no desenvolvimento de aplicações como no modo script.)
  • Utiliza sistemas de tradução de Rotas
  • Facilidade na resolução de erro
  • Padrão MVC
  • Assíncrono (I/O não bloqueante)
  • Stateless
  • Arquitetura RESTful ( REST (ou Representational State Transfer) é um estilo de desenvolvimento para sistemas distribuídos que privilegia a trasferência de estado sem envolver camadas de mapeamento (como o SOAP faz). Assim, os verbos GET, POST, PUT e DELETE mapeam quase que diretamente para ações READ, UPDATE, CREATE e DELETE (CRUD).
  • Persistência com JPA (JPA é uma especificação de Persistência da plataforma Java, para persistir as classes java em bancos de dados relacionais. )
  • Extensível (Através de Módulos / Bibliotecas Java)
  • TDD – Test Development Drive (Test Driven Development (TDD) ou em português Desenvolvimento dirigido por testes )

 

Como iniciar uma aplicação no Play?

É facil, basta usar o comando no consolhe (Terminal no Linux e Prompt de comando no Windows, lembrando que você terá que estar dentro da pasta do framework no windows e no linux ter adicionado o caminho da pasta ao PATH para executar o comando play):

play new nomedaaplicacao

Toda a estrutura do projeto será criada, incluindo arquivos de configuração e o roteamento inicial da aplicação. Se você deseja abrir o projeto no Eclipse ou no Netbeans, o Play! cria o projeto para você. Basta fazer assim:

play eclipsify nomedaaplicacao

Ou se preferir o Netbeans:

play netbeansify nomedaaplicacao

Dessa forma, você poderá importar o projeto de sua IDE e todas as configurações estarão realizadas. Outro comando importante é a gerador de war (deploy).

 play war nomeDoProjeto -o nomeDoProjeto.war

Pronto, feito isto basta começar a programar no projeto usando Java ou Scala 🙂 !

Slide da apresentação feita na SWX: play-framework-apresentaçao

Código de uma pequena aplicação de uma agenda feita na SWX:

No diretório /conf no arquivo application.conf , caso use mysql, basta localizar e modificar o padrão para seu usuário e senha do mysql e o nome do banco (No exemplo a seguir está sem senha).

# To connect to a local MySQL5 database, use:
db=mysql:acson@minha_agenda
// acson -> usuário do banco,  minha_agenda -> banco

No diretório /app/controllers , modifique o Application.java (ou crie se não existir)  para:

package controllers;
import play.*;
import play.mvc.*;
import play.data.validation.*;
import java.util.*;
import models.*;
public class Application extends Controller {
public static void index() {
 List<Contato> contatos = Contato.find("order by nome asc").fetch();
 render(contatos);
 }
public static void inserir() {
 render();
 }

 public static void visualizar(String email) {
 Contato contato = Contato.find("email", email).first();
 render(contato);
 }

 public static void editar(String email) {
 Contato contato = Contato.find("email", email).first();
 render(contato);
 }

 public static void excluir(String email) {
 Contato contato = Contato.find("email", email).first();
 contato.delete();
 index();
 }

 public static void cadastrar_contato(@Required String nome, @Required String email, String telefone, String twitter, String skype) {
 Contato contato = new Contato(nome, email, telefone, twitter, skype);
 if (validation.hasErrors()) {
 render("Application/inserir.html", contato);
 }

 contato.save();
 index();
 }

 public static void editar_contato(long id) {
 validation.required(request.params.get("nome"));
 validation.required(request.params.get("email"));

 Contato contato = Contato.find("id", id).first();

 if (validation.hasErrors()) {
 render("Application/editar.html", contato);
 }

 contato.nome = request.params.get("nome");
 contato.telefone = request.params.get("telefone");
 contato.email = request.params.get("email");
 contato.twitter = request.params.get("twitter");
 contato.skype = request.params.get("skype");

 contato.save();
 index();
 }
}

 

No diretório /app/models  , crie a classe Contato (Contato.java) com o seguinte código:

package models;
import play.*;
import play.db.jpa.*;
import javax.persistence.*;
import java.util.*;
@Entity
public class Contato extends Model {

 public String nome;
 public String email;

 public String telefone;
 public String twitter;
 public String skype;

 public Contato(String nome, String email, String telefone, String twitter, String skype) {
 this.nome = nome;
 this.email = email;
 this.telefone = telefone;
 this.twitter = twitter;
 this.skype = skype;
 }

}

No diretório /app/views  , crie o arquivo application.html com o seguinte código:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>.: Agenda de Contatos - #{get 'title' /}</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/principal.css'}">
 #{get 'moreStyles' /}
 <script src="@{'/public/javascripts/jquery-1.4.2.min.js'}" type="text/javascript" charset="utf-8"></script>
 #{get 'moreScripts' /}
</head>
<body id="page1">
 <div id="geral">

 <div id="conteudo">
 <div id="logo"></div>
 <div class="linha">
 <div class="titulo">.: Agenda de Contatos</div>
 #{if request.actionMethod != "inserir" && request.actionMethod != "editar"}
 <div class="text"><a href="@{Application.inserir()}" class="button">+ Incluir Contato</a></div>
 #{/if}
 </div>
 <div class="linha"></div>
 #{doLayout /}
 </div>
 </div>
 </div>
</body>
</html>

No diretório /app/views/Application  , crie o arquivo inserir.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Inclusão' /}
#{form @Application.cadastrar_contato()}
 #{ifErrors}
 <div class="linha"><p style="color:red;"><strong>ATENÇÃO: </strong>Preencha todos os campos obrigatórios.</p></div>
 <div class="linha"></div>
 #{/ifErrors}
<div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="nome">Nome:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="nome" id="nome" value="${params.nome}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="telefone">Telefone:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="telefone" id="telefone" value="${params.telefone}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="email">Email:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="email" id="email" value="${params.email}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="twitter">Twitter:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="twitter" id="twitter" value="${params.twitter}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="skype">Skype:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="skype" id="skype" value="${params.skype}" /></p>
 </div>
 </div>
 </div>
 <div class="btn-submit">
 <p><input type="submit" value="Cadastrar o Contato" /></p>
 </div>

#{/form}

No diretório /app/views/Application  , crie o arquivo visualizar.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Visualiza‹o' /}
<div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="nome">Nome:</label></p>
 </div>
 <div class="dir">
 <p>${contato.nome}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="telefone">Telefone:</label></p>
 </div>
 <div class="dir">
 <p>${contato.telefone}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="email">Email:</label></p>
 </div>
 <div class="dir">
 <p>${contato.email}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="twitter">Twitter:</label></p>
 </div>
 <div class="dir">
 <p>${contato.twitter}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="skype">Skype:</label></p>
 </div>
 <div class="dir">
 <p>${contato.skype}</p>
 </div>
 </div>
 </div>
 <div class="btn-submit">
 <p>
 <a href="@{Application.index()}">Cancelar</a>
 <a href="@{Application.editar(contato.email)}">Editar</a>
 <a href="@{Application.excluir(contato.email)}" onClick="if(!confirm('Deseja excluir este contato?')){return false;}">Excluir</a>
 </p>
 </div>

No diretório /app/views/Application  , crie o arquivo editar.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Edição' /}
#{form @Application.editar_contato(contato.id)}
 #{ifErrors}
 <div class="linha"><p style="color:red;"><strong>ATENÇÃO: </strong>Preencha todos os campos obrigatórios.</p></div>
 <div class="linha"></div>
 #{/ifErrors}
<div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="nome">Nome:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="nome" id="nome" value="${contato.nome}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="telefone">Telefone:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="telefone" id="telefone" value="${contato.telefone}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="email">Email:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="email" id="email" value="${contato.email}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="twitter">Twitter:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="twitter" id="twitter" value="${contato.twitter}"/></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="skype">Skype:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="skype" id="skype" value="${contato.skype}" /></p>
 </div>
 </div>
 </div>
 <div class="btn-submit">
 <p><input type="submit" value="Editar o Contato" /></p>
 </div>

#{/form}

No diretório /app/views/Application  , crie o arquivo index.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Listagem' /}
#{if contatos.size() == 0}
 <div class="linha">
 <p>Nenhum contato cadastrado.</p>
 </div>
#{/if}
#{else}
 #{list items:contatos, as:'contato'}
 <div class="linha">
 <p><a href="@{Application.visualizar(contato.email)}">&raquo; ${contato.nome} - ${contato.email}</a></p>
 </div>
 #{/list}
#{/else}

E para ficar mais agradável e padronizado, vamos mudar o arquivo de rotas que fica em  /conf , o arquivo é o routes

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / Application.index
GET /cadastrar Application.inserir
GET /visualizar/{email} Application.visualizar
GET /editar/{email} Application.editar
GET /excluir/{email} Application.excluir
# Map static resources from the /app/public folder to the /public path
GET /public/ staticDir:public
# Catch all
* /{controller}/{action} {controller}.{action}

Quando o usuário chamar o método de inserir que está no Application.java, no browser aparecerá dominio/cadastrar, e assim por diante.
Terminando isso o aplicativo está pronto para uso.
Abaixo algumas telas de uma pequena aplicação que fizemos, uma agenda de contados:

Site oficial do Play Framework: http://www.playframework.org/

Github do Play Framework:  https://github.com/playframework/play

Algumas fontes consultadas: Imasters, Bragil.net

Desenvolvimento de Web APIs evolui no ASP.NET MVC 4

Fonte: Elemar Jr./InfoQ

A nova versão do framework para desenvolvimento de aplicativos Web da Microsoft, o ASP.NET MVC 4, amplia muito o suporte ao desenvolvimento de aplicações Web API. O framework, agora integralmente open source e disponível no Codeplex, possibilita o desenvolvimento de serviços RESTful com pouco esforço.

Entre as novidades na versão 4, destacam-se a facilidade para criar rotas para recursos (evitando colisão com rotas padrões MVC), a escrita de Actions para cada um dos métodos HTTP, o suporte nativo ao fornecimento de objetos em formato JSON e XML, além do suporte ampliado a URLs de consulta compatíveis com OData.

O ASP.NET MVC Web API permite um novo modelo de desenvolvimento web, em que o servidor provê apenas conteúdo e a geração da apresentação ocorre inteiramente no browser. Ou seja, no lugar de prover o HTML pronto, o servidor pode entregar um composto HTML + JavaScript, deixando que os dados sejam requisitados conforme demanda, via Ajax, para um serviço RESTful. (Importante destacar que o template padrão para aplicações ASP.NET MVC já possui referências para JQuery.) A possibilidade de gerar, automaticamente, respostas em formato JSON facilita consideravelmente a manipulação de código JavaScript.

As novas funcionalidades já são suportadas tanto no novo Visual Studio 11 (ainda beta e disponível para download na versão Ultimate), quanto no Visual Studio 2010 (mediante instalação).

Conforme noticiamos aqui, embora o ASP.NET MVC 4 não esteja completo, a Microsoft já recomenda sua utilização em produção. A Microsoft disponibilizou um mini-tutorial sobre o framework, com artigos e vídeos.

REST tem impacto sobre NoSQL?

A partir do momento que grandes empresas como o Twitter e a Amazon abraçaram a arquitetura REST e também se tornaram defensores do NoSQL tornou-se inevitável assistirmos a essas duas tecnologias sendo utilizadas em conjunto. Em um post recente, Ganesh Prasad questiona como o sucesso do NoSQL nos leva a reavaliar os aspectos centrais do REST. Ganesh acredita que existem dois aspectos na tecnologia que representam obstáculos para a sua adoção:

Um deles é o uso do modelo cliente/servidor, ao invés do modelo de ponto a ponto, que acredito ser mais geral e útil. O segundo é a insistência na ausência de estado do cliente no servidor, forçando que essas informações sejam armazenadas no próprio cliente ou que sejam modeladas como recursos.

É no aspecto da ausência de estado que Ganesh se concentra. A questão de manutenção de estado e o REST já foi muito debatida em várias fontes, por exemplo Bill Burke discutiu essa questão anos atrás:

Em REST, a ausência de estado significa que não existem dados da sessão do cliente armazenados no servidor. O servidor somente cuida do estado dos recursos que expõe. Se houver necessidade de informações específicas da sessão de algum cliente, essas informações devem ser armazenadas no próprio cliente e transferidas para o servidor a cada requisição, quando necessário.

A camada de serviços que não mantém informações dos clientes conectados é muito mais simples de escalar, por precisar de menos informações ao se replicar em um ambiente em cluster. É mais simples de colocar em cluster, porque tudo o que é preciso fazer é adicionar mais máquinas.

Stefan Tilkov adota a mesma linha:

É importante reforçar que, embora REST inclua a ideia da ausência de estado, isso não significa que a aplicação que expõe suas funcionalidades não pode ter estado – isso tornaria essa abordagem pouco útil para a maioria dos cenários.


O REST obriga que o estado seja transformado em um recurso ou mantido no cliente. Em outras palavras, o servidor não deve manter nenhum tipo de informação associada ao estado da comunicação com o cliente, independente do da duração de uma requisição. A principal razão para isso é a escalabilidade: a capacidade de atendimento dos servidores fica severamente prejudicada quando o servidor necessita manter o estado das comunicações. (Note que essa restrição exige modificações na aplicação: não se pode simplesmente atribuir uma URI a um estado da sessão e chamar a aplicação de RESTful.)


Existem outros aspectos mais importantes: a ausência de estado isola o cliente de alterações dos servidores, uma vez que não depende da comunicação com o mesmo servidor em duas requisições consecutivas. O cliente pode receber um “documento” contendo links de um servidor e, enquanto o cliente processa essas informações, o mesmo servidor pode ser desligado; o disco removido e trocado; e o software atualizado e reiniciado; tudo isso sem impacto negativo. Se o cliente seguir os links obtidos a partir do servidor, ele não irá perceber.

Ganesh, apesar de entender que a ausência de estado colabora com demandas de escalabilidade e recuperação a falhas, acredita que tais restrições sobrecarregam a camada da aplicação, que passa a ter de tratar aspectos de distribuição e infraestrutura:

A abordagem REST é aceitável para elementos do domínio da aplicação, mas a existência de estado de comunicação com o cliente é útil para tratar elementos independentes do domínio, associados à qualidade do serviço como, por exemplo chaves de sessão para o controle de segurança. A recusa do REST em suportar aspectos como esses compromete a habilidade de oferecer essas características de forma transparente.

É para esse tipo de estado referenciado por Bill e Stefan que Ganesh chama atenção. Ganesh destaca que o NoSQL oferece uma solução escalável e tolerante a falhas para o problema. Ele se refere à implementação do Redis, entretanto a maioria (se não todas) as implementações NoSQL também tratam deste problema.

Está se tornando uma recomendação armazenar o estado da sessão em um banco de dados NoSQL como o Redis, ao invés de em memória. Delegar o armazenamento dos dados de sessão para um cluster NoSQL independente, e configurar os servidores de aplicação para obtê-las a partir deste cluster, torna os servidores de aplicações independentes dos clientes novamente. Um destaque no Redis é a baixa complexidade das operações GET e SET, que são de Ordem(1), ou seja, constante. Isto significa que (pelo menos em teoria) o número de clientes utilizando um banco de dados Redis pode aumentar indefinidamente, sem impacto na performance.

O artigo de Ganesh descreve como podemos utilizar o banco de dados NoSQL Redis para gerenciar os dados de sessão. Desta forma, acredita ele, aplicações REST devem ser levadas seriamente em consideração (neste caso sendo necessário atualizar/aprimorar a filosofia do REST). Ele conclui dizendo:

Seria bom se um mecanismo padrão e sem dependência de domínio pudesse evoluir para fornecer segurança e confiabilidade às interações baseadas em REST, utilizando mecanismos de armazenamento escalável de sessões em NoSQL.

A maioria das metodologias de desenvolvimento, frameworks e padrões mantém a sua relevância evoluindo para novas abordagens, assim que novas experiências são obtidas. NoSQL era apenas um exercício acadêmico quando a arquitetura REST foi proposta, portanto surge a questão: a arquitetura REST precisa evoluir face ao NoSQL, ou a natureza sem estado do REST continua a ser uma exigência, independentemente da abordagem utilizada para armazená-lo?

Fonte: Mark Little , traduzido por Lucas Machado/InfoQ