Introdução ao RESTX
1. Visão geral
Neste tutorial, faremos um tour pela estrutura leve Java RESTRESTX.
2. Recursos
Construir uma API RESTful é bastante fácil com a estrutura RESTX. Ele possui todos os padrões que podemos esperar de uma estrutura REST, como servir e consumir JSON, parâmetros de consulta e caminho, mecanismos de roteamento e filtragem, estatísticas de uso e monitoramento.
O RESTX também vem com um console da web de administração intuitivo e instalador de linha de comando para facilitar a inicialização.
Ele também é licenciado pela Licença Apache 2 e mantido por uma comunidade de desenvolvedores. O requisito mínimo de Java para o RESTX é o JDK 7.
3. Configuração
O RESTX vem com um aplicativo shell / comando útil que é útil para inicializar rapidamente um projeto Java.
Precisamos instalar o aplicativo antes de prosseguir. A instrução de instalação detalhada está disponívelhere.
4. Instalando plugins principais
Agora é hora de instalar os plug-ins principais para poder criar um aplicativo a partir do próprio shell.
No shell RESTX, vamos executar o seguinte comando:
shell install
Em seguida, solicitará que você selecione os plugins para instalação. Precisamos selecionar o número que aponta paraio.restx:restx-core-shell. The shell will automatically restart once installation completes.
5. Shell App Bootstrap
Usando o shell RESTX, é muito conveniente inicializar um novo aplicativo. Ele fornece um guia baseado em assistente.
Começamos executando o seguinte comando no shell:
app new
Este comando acionará o assistente. Em seguida, podemos escolher as opções padrão ou alterá-las conforme nossos requisitos:
Como escolhemos gerar umpom.xml,, o projeto pode ser facilmente importado para qualquer IDE Java padrão.
Em alguns casos, podemos precisar ajustarthe IDE settings.
Nosso próximo passo será construir o projeto:
mvn clean install -DskipTests
Once the build is successful we can run the AppServer class as a Java Application from the IDE. Isso iniciará o servidor com o console administrativo, escutando na porta 8080.
Podemos navegar atéhttp://127.0.0.1:8080/api/@/ui e ver a IU básica.
As rotas que começam com/@/ são usadas para o console de administração, que é um caminho reservado em RESTX.
Para entrar no console de administração, podemos usar o nome de usuário padrão “admin“e a senha que fornecemos ao criar o aplicativo.
Antes de brincarmos com o console, vamos explorar o código e entender o que o assistente gerou.
6. Um recurso RESTX
As rotas são definidas na classe <main_package>.rest.HelloResource:
@Component
@RestxResource
public class HelloResource {
@GET("/message")
@RolesAllowed(Roles.HELLO_ROLE)
public Message sayHello() {
return new Message().setMessage(String.format("hello %s, it's %s",
RestxSession.current().getPrincipal().get().getName(),
DateTime.now().toString("HH:mm:ss")));
}
}
É imediatamente aparente que RESTX usa anotações J2EE padrão para segurança e ligações REST. Na maioria das vezes, ele usa suas próprias anotações para injeção de dependência.
RESTX também suporta muitos padrões razoáveis paramapping method parameters to the request.
E, além dessas anotações padrão, está@RestxResource, que o declara como um recurso que o RESTX reconhece.
O caminho base é adicionado emsrc/main/webapp/WEB-INF/web.xml.. Em nosso caso, é/api, então podemos enviar uma solicitação GET parahttp://localhost:8080/api/message, assumindo a autenticação adequada.
A classeMessage é apenas um bean Java que o RESTX serializa para JSON.
Controlamos o acesso do usuário especificando a anotaçãoRolesAllowed usando oHELLO_ROLE que foi gerado pelo bootstrapper.
7. A classe do módulo
Conforme observado anteriormente, RESTX usa anotações de injeção de dependência padrão J2EE, como@Named, e inventa suas próprias onde necessário, provavelmente seguindo uma sugestão da estrutura Dagger para@Modulee@Provides.
Ele os usa para criar o módulo principal do aplicativo, que, entre outras coisas, define a senha do administrador:
@Module
public class AppModule {
@Provides
public SignatureKey signatureKey() {
return new SignatureKey("restx-demo -44749418370 restx-demo 801f-4116-48f2-906b"
.getBytes(Charsets.UTF_8));
}
@Provides
@Named("restx.admin.password")
public String restxAdminPassword() {
return "1234";
}
@Provides
public ConfigSupplier appConfigSupplier(ConfigLoader configLoader) {
return configLoader.fromResource("restx/demo/settings");
}
// other provider methods to create components
}
@Module define uma classe que pode definir outros componentes, semelhante a@Module em Dagger ou@Configuration in Spring.
@Provides expõe um componente programaticamente, como@Provides in Dagger ou@Bean no Spring.
E, por fim, a anotação@Named é utilizada para indicar o nome do componente produzido.
AppModule também fornece umSignatureKey usado para assinar o conteúdo enviado aos clientes. Ao criar a sessão para o aplicativo de amostra, por exemplo, isso definirá um cookie assinado com a chave configurada:
HTTP/1.1 200 OK
...
Set-Cookie: RestxSessionSignature-restx-demo="ySfv8FejvizMMvruGlK3K2hwdb8="; RestxSession-restx-demo="..."
...
E verifiqueRESTX’s components factory/dependency injection documentation para mais.
8. A classe Launcher
E, por último, a classeAppServer é usada para executar o aplicativo como um aplicativo Java padrão em um servidor Jetty incorporado:
public class AppServer {
public static final String WEB_INF_LOCATION = "src/main/webapp/WEB-INF/web.xml";
public static final String WEB_APP_LOCATION = "src/main/webapp";
public static void main(String[] args) throws Exception {
int port = Integer.valueOf(Optional.fromNullable(System.getenv("PORT")).or("8080"));
WebServer server =
new Jetty8WebServer(WEB_INF_LOCATION, WEB_APP_LOCATION, port, "0.0.0.0");
System.setProperty("restx.mode", System.getProperty("restx.mode", "dev"));
System.setProperty("restx.app.package", "restx.demo");
server.startAndAwait();
}
}
Aqui, o mododev é usado durante a fase de desenvolvimento para habilitar recursos como a compilação automática que encurta o ciclo de feedback de desenvolvimento.
Podemos empacotar o aplicativo como um arquivowar (arquivo da web) para implantar em um contêiner da web J2EE independente.
Vamos descobrir como testar o aplicativo na próxima seção.
9. Teste de integração usando especificações
Um dos fortes recursos do RESTX é o conceito de "especificações". Uma amostraspec ficaria assim:
title: should admin say hello
given:
- time: 2013-08-28T01:18:00.822+02:00
wts:
- when: |
GET hello?who=xavier
then: |
{"message":"hello xavier, it's 01:18:00"}
O teste é escrito em uma estruturaGiven-When-Then dentro de um arquivoYAML que basicamente define como a API deve responder (then) a uma solicitação específica (when) dado um estado atual do sistema (given).
A classeHelloResourceSpecTest emsrc/test/resources acionará os testes escritos nas especificações acima:
@RunWith(RestxSpecTestsRunner.class)
@FindSpecsIn("specs/hello")
public class HelloResourceSpecTest {}
A classeRestxSpecTestsRunner é umacustom JUnit runner. Ele contém regras JUnit personalizadas para:
-
configurar um servidor incorporado
-
preparar o estado do sistema (de acordo com a seçãogiven nas especificações)
-
emitir as solicitações especificadas e
-
verifique as respostas esperadas
A anotação@FindSpecsIn aponta para o caminho dos arquivos de especificação nos quais os testes devem ser executados.
As especificações deThe spec helps to write integration tests and provide examples in the API docs. também são úteis paramock HTTP requests and record request/response pairs.
10. Teste manual
Também podemos testar manualmente através de HTTP. Primeiro, precisamos fazer login e, para fazer isso, precisamos fazer o hash da senha de administrador no console RESTX:
hash md5
E então podemos passar isso para o endpoint/sessions:
curl -b u1 -c u1 -X POST -H "Content-Type: application/json"
-d '{"principal":{"name":"admin","passwordHash":"1d528266b85cf052803a57288"}}'
http://localhost:8080/api/sessions
(Observe que os usuários do Windows precisamdownload curl primeiro.)
E agora, se usarmos a sessão como parte de nossa solicitação/message:
curl -b u1 "http://localhost:8080/api/message?who=restx"
Então obteremos algo assim:
{"message" : "hello admin, it's 09:56:51"}
11. Explorando o Admin Console
O console do administrador fornece recursos úteis para controlar o aplicativo.
Vamos dar uma olhada nos principais recursos navegando atéhttp://127.0.0.1:8080/admin/@/ui.
11.1. API Docs
A seção de documentos da API lista todas as rotas disponíveis, incluindo todas as opções:
E podemos clicar em rotas individuais e experimentá-las no próprio console:
11.2. Monitoramento
A seçãoJVM Metrics mostra as métricas do aplicativo com sessões ativas, uso de memória e despejo de thread:
EmApplication Metrics, temos principalmente duas categorias de elementos monitorados por padrão:
-
BUILD corresponde à instanciação dos componentes do aplicativo
-
HTTP corresponde a solicitações HTTP tratadas por RESTX
11.3. Estatísticas
O RESTX permite que o usuário escolha coletar e compartilhar estatísticas anônimas no aplicativo para fornecer informações à comunidade RESTX. We can easily opt out by excluding the restx-stats-admin module.
As estatísticas relatam coisas como o SO subjacente e a versão da JVM:
Because this page shows sensitive information,make sure to review its configuration options.
Além disso, o console de administração também pode nos ajudar:
-
verifique os logs do servidor (Logs)
-
ver os erros encontrados (erros)
-
verifique as variáveis de ambiente (Config)
12. Autorização
RESTX endpoints are secured by default. Isso significa que se para qualquer ponto de extremidade:
@GET("/greetings/{who}")
public Message sayHello(String who) {
return new Message(who);
}
Quando chamado sem autenticação, retornará401 por padrão.
Para tornar um endpoint público, precisamos usar a anotação@PermitAll no método ou no nível da classe:
@PermitAll
@GET("/greetings/{who}")
public Message sayHello(String who) {
return new Message(who);
}
Observe que, no nível da classe, todos os métodos são públicos.
Além disso, a estrutura também permite especificar funções de usuário usando a anotação@RolesAllowed:
@RolesAllowed("admin")
@GET("/greetings/{who}")
public Message sayHello(String who) {
return new Message(who);
}
Com esta anotação, o RESTX verificará se o usuário autenticado também possui uma função de administrador atribuída. No caso de um usuário autenticado sem funções administrativas tentar acessar o endpoint, o aplicativo retornará um403 enão em vez de um401.
Por padrão, as funções e credenciais do usuário são armazenadas no sistema de arquivos, em arquivos separados.
Portanto, a id do usuário com a senha criptografada é armazenada no arquivo/data/credentials.json:
{
"user1": "$2a$10$iZluUbCseDOvKnoe",
"user2": "$2a$10$oym3Swr7pScdiCXu"
}
E, as funções do usuário são definidas no arquivo/data/users.json:
[
{"name":"user1", "roles": ["hello"]},
{"name":"user2", "roles": []}
]
No aplicativo de amostra, os arquivos são carregados emAppModule por meio da classeFileBasedUserRepository:
new FileBasedUserRepository<>(StdUser.class, mapper,
new StdUser("admin", ImmutableSet. of("*")),
Paths.get("data/users.json"), Paths.get("data/credentials.json"), true)
A classeStdUser contém os objetos do usuário. Pode ser uma classe de usuário customizada, mas precisa ser serializável no JSON.
Podemos, é claro, usar uma implementaçãoUserRepository diferente, como uma que atinge um banco de dados.
13. Conclusão
Este tutorial deu uma visão geral da estrutura RESTX leve baseada em Java.
A estrutura ainda está em desenvolvimento e pode haver algumas arestas em sua utilização. Confirathe official documentation para mais detalhes.
O aplicativo inicializado de amostra está disponível em nossoGitHub repository.