Criando microsserviços REST com Javalin

Criando microsserviços REST com Javalin

1. Introdução

Javalin é uma estrutura leve da web escrita para Java e Kotlin. Ele é escrito na parte superior do servidor da web Jetty, o que o torna de alto desempenho. Javalin é modelado de forma semelhante akoa.js, o que significa que foi escrito do zero para ser simples de entender e construir.

Neste tutorial, vamos percorrer as etapas de construção de um microsserviço REST básico usando esta estrutura leve.

2. Adicionando dependências

Para criar um aplicativo básico, precisamos apenas de uma dependência - o próprio Javalin:


    io.javalin
    javalin
    1.6.1

A versão atual pode ser encontradahere.

3. Configurando Javalin

O Javalin facilita a configuração de um aplicativo básico. Vamos começar definindo nossa classe principal e configurando um aplicativo simples “Hello World”.

Vamos criar um novo arquivo em nosso pacote base chamadoJavalinApp.java.

Dentro deste arquivo, criamos um método principal e adicionamos o seguinte para configurar um aplicativo básico:

Javalin app = Javalin.create()
  .port(7000)
  .start();
app.get("/hello", ctx -> ctx.html("Hello, Javalin!"));

Estamos criando uma nova instância de Javalin, fazendo com que escute na porta 7000 e, em seguida, iniciando o aplicativo.

Também estamos configurando nosso primeiro endpoint para ouvir uma solicitaçãoGET no endpoint /hello.

Vamos executar este aplicativo e visitarhttp://localhost:7000/hello para ver os resultados.

4. Criando umUserController

Um exemplo “Hello World” é ótimo para introduzir um tópico, mas não é benéfico para um aplicativo real. Vamos ver um caso de uso mais realista para Javalin agora.

Primeiro, precisamos criar um modelo do objeto com o qual estamos trabalhando. Começamos criando um pacote chamadouser no projeto raiz.

Em seguida, adicionamos uma nova classeUser:

public class User {
    public final int id;
    public final String name;

    // constructors
}

Além disso, precisamos configurar nosso objeto de acesso a dados (DAO). Usaremos um objeto na memória para armazenar nossos usuários neste exemplo.

Criamos uma nova classe no pacoteuser chamadaUserDao.java:

class UserDao {

    private List users = Arrays.asList(
      new User(0, "Steve Rogers"),
      new User(1, "Tony Stark"),
      new User(2, "Carol Danvers")
    );

    private static UserDao userDao = null;

    private UserDao() {
    }

    static UserDao instance() {
        if (userDao == null) {
            userDao = new UserDao();
        }
        return userDao;
    }

    Optional getUserById(int id) {
        return users.stream()
          .filter(u -> u.id == id)
          .findAny();
    }

    Iterable getAllUsernames() {
        return users.stream()
          .map(user -> user.name)
          .collect(Collectors.toList());
    }
}

A implementação de nosso DAO como um singleton facilita o uso no exemplo. Também poderíamos declará-lo como um membro estático da nossa classe principal ou usar injeção de dependência de uma biblioteca como o Guice, se quiséssemos.

Finalmente, queremos criar nossa classe de controlador. O Javalin nos permite ser muito flexíveis quando declaramos nossos manipuladores de rota, portanto essa é apenas uma maneira de defini-los.

Criamos uma nova classe chamadaUserController.java no pacoteuser:

public class UserController {
    public static Handler fetchAllUsernames = ctx -> {
        UserDao dao = UserDao.instance();
        Iterable allUsers = dao.getAllUsernames();
        ctx.json(allUsers);
    };

    public static Handler fetchById = ctx -> {
        int id = Integer.parseInt(Objects.requireNonNull(ctx.param("id")));
        UserDao dao = UserDao.instance();
        User user = dao.getUserById(id);
        if (user == null) {
            ctx.html("Not Found");
        } else {
            ctx.json(user);
        }
    };
}

Ao declarar os manipuladores como estáticos, garantimos que o próprio controlador não possua nenhum estado. Mas, em aplicativos mais complexos, podemos querer armazenar o estado entre as solicitações, caso em que precisaríamos remover o modificador estático.

Observe também que o teste de unidade é mais difícil com métodos estáticos; portanto, se quisermos esse nível de teste, precisaremos usar métodos não estáticos.

5. Adicionando Rotas

Agora, temos várias maneiras de buscar dados do nosso modelo. A última etapa é expor esses dados pelos pontos de extremidade REST. Precisamos registrar duas novas rotas em nosso aplicativo principal.

Vamos adicioná-los à nossa classe de aplicativo principal:

app.get("/users", UserController.fetchAllUsernames);
app.get("/users/:id", UserController.fetchById);

Após compilar e executar o aplicativo, podemos fazer uma solicitação para cada um desses novos pontos de extremidade. Chamarhttp://localhost:7000/users will lista todos os usuários e chamarhttp://localhost:7000/users/0 will obtém o único objeto JSON do usuário com o id 0. Agora temos um microsserviço que nos permite recuperar dados deUser.

6. Extensão de rotas

A recuperação de dados é uma tarefa vital da maioria dos microsserviços.

No entanto, também precisamos armazenar dados em nosso armazenamento de dados. O Javalin fornece o conjunto completo de manipuladores de caminho necessários para criar serviços.

Vimos um exemplo deGET acima, masPATCH, POST, DELETE, andPUT também são possíveis.

Além disso, se incluirmos Jackson como uma dependência, poderemos analisar os corpos de solicitação JSON automaticamente em nossas classes de modelo. Por exemplo:

app.post("/") { ctx ->
  User user = ctx.bodyAsClass(User.class);
}

nos permitiria pegar o objeto JSONUser do corpo da solicitação e convertê-lo no objeto de modeloUser.

7. Conclusão

Podemos combinar todas essas técnicas para fazer nosso microsserviço.

Neste artigo, vimos como configurar o Javalin e criar um aplicativo simples. Também falamos sobre como usar os diferentes tipos de métodos HTTP para permitir que os clientes interajam com nosso serviço.

Para obter exemplos mais avançados de como usar Javalin, certifique-se de verificar odocumentation.

Além disso, como sempre, o código pode ser encontradoover on GitHub.