Создание REST Microservices с помощью Javalin

Создание микросервисов REST с Javelin

1. Вступление

Javalin - это легкий веб-фреймворк, написанный для Java и Kotlin. Он написан поверх веб-сервера Jetty, что обеспечивает его высокую производительность. Джавалин очень похож наkoa.js, что означает, что он написан с нуля, чтобы его было легко понять и развить.

В этом руководстве мы рассмотрим этапы создания базового микросервиса REST с использованием этой легкой инфраструктуры.

2. Добавление зависимостей

Для создания базового приложения нам нужна только одна зависимость - сам Джавалин:


    io.javalin
    javalin
    1.6.1

Текущую версию можно найтиhere.

3. Настройка Джавалина

Javalin упрощает настройку базового приложения. Мы собираемся начать с определения нашего основного класса и создания простого приложения «Hello World».

Давайте создадим новый файл в нашем базовом пакете с именемJavalinApp.java.

Внутри этого файла мы создаем метод main и добавляем следующее для настройки базового приложения:

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

Мы создаем новый экземпляр Javalin, заставляем его прослушивать порт 7000, а затем запускаем приложение.

Мы также настраиваем нашу первую конечную точку для прослушивания запросаGET в конечной точке /hello.

Давайте запустим это приложение и посетимhttp://localhost:7000/hello, чтобы увидеть результаты.

4. СозданиеUserController

Пример «Hello World» отлично подходит для введения в тему, но бесполезен для реального приложения. Давайте теперь рассмотрим более реалистичный вариант использования Javalin.

Во-первых, нам нужно создать модель объекта, с которым мы работаем. Начнем с создания пакета под названиемuser в корневом проекте.

Затем мы добавляем новый классUser:

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

    // constructors
}

Также нам нужно настроить наш объект доступа к данным (DAO). В этом примере мы будем использовать объект в памяти для хранения наших пользователей.

Мы создаем новый класс в пакетеuser с именемUserDao.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());
    }
}

Реализация нашего DAO в качестве одиночного облегчает использование в этом примере. Мы также можем объявить его как статический член нашего основного класса или использовать внедрение зависимостей из библиотеки, такой как Guice, если захотим.

Наконец, мы хотим создать наш класс контроллера. Javelin позволяет нам быть очень гибкими, когда мы объявляем наши обработчики маршрутов, так что это только один из способов их определения.

Мы создаем новый класс с именемUserController.java в пакетеuser:

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);
        }
    };
}

Объявляя обработчики как статические, мы гарантируем, что сам контроллер не содержит состояния. Но в более сложных приложениях мы можем захотеть сохранять состояние между запросами, и в этом случае нам нужно удалить статический модификатор.

Также обратите внимание, что модульное тестирование сложнее при использовании статических методов, поэтому, если нам нужен такой уровень тестирования, нам нужно будет использовать нестатические методы.

5. Добавление маршрутов

Теперь у нас есть несколько способов получения данных из нашей модели. Последний шаг - предоставить эти данные через конечные точки REST. Нам нужно зарегистрировать два новых маршрута в нашем основном приложении.

Давайте добавим их в наш основной класс приложения:

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

После компиляции и запуска приложения мы можем сделать запрос к каждой из этих новых конечных точек. Вызовhttp://localhost:7000/users will перечисляет всех пользователей и вызовhttp://localhost:7000/users/0 will получает единственный объект User JSON с идентификатором 0. Теперь у нас есть микросервис, который позволяет нам получать данныеUser.

6. Расширение маршрутов

Получение данных является жизненно важной задачей большинства микросервисов.

Однако нам также необходимо иметь возможность хранить данные в нашем хранилище данных. Javelin предоставляет полный набор обработчиков путей, необходимых для построения сервисов.

Мы видели примерGET выше, ноPATCH, POST, DELETE, andPUT также возможны.

Также, если мы включим Джексона в качестве зависимости, мы можем автоматически анализировать тела запросов JSON в наших модельных классах. Например:

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

позволит нам получить объект JSONUser из тела запроса и преобразовать его в объект моделиUser.

7. Заключение

Мы можем объединить все эти методы, чтобы сделать наш микросервис.

В этой статье мы увидели, как настроить Javalin и создать простое приложение. Мы также говорили о том, как использовать различные типы HTTP-методов, чтобы клиенты могли взаимодействовать с нашим сервисом.

Для более сложных примеров использования Javalin обязательно ознакомьтесь сdocumentation.

Также как всегда можно найти кодover on GitHub.