«1. Обзор

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

2. Возможности

Создать RESTful API довольно просто с помощью RESTX framework. Он имеет все значения по умолчанию, которые мы можем ожидать от среды REST, такие как обслуживание и использование JSON, параметры запроса и пути, механизмы маршрутизации и фильтрации, статистика использования и мониторинг.

RESTX также поставляется с интуитивно понятной веб-консолью администратора и установщиком командной строки для простой загрузки.

Он также находится под лицензией Apache License 2 и поддерживается сообществом разработчиков. Минимальное требование Java для RESTX — JDK 7.

3. Конфигурация

RESTX поставляется с удобной оболочкой/командным приложением, которое полезно для быстрой загрузки проекта Java.

Нам нужно сначала установить приложение, прежде чем мы сможем продолжить. Подробная инструкция по установке доступна здесь.

4. Установка основных плагинов

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

В оболочке RESTX запустим следующую команду:

shell install

Затем нам будет предложено выбрать плагины для установки. Нам нужно выбрать номер, который указывает на io.restx:restx-core-shell. Оболочка автоматически перезапустится после завершения установки.

5. Начальная загрузка приложения оболочки

Используя оболочку RESTX, очень удобно загружать новое приложение. Он предоставляет руководство на основе мастера.

Мы начинаем с выполнения следующей команды в оболочке:

app new

Эта команда запускает мастер. Затем мы можем либо использовать параметры по умолчанию, либо изменить их в соответствии с нашими требованиями:

Поскольку мы решили сгенерировать pom.xml, проект можно легко импортировать в любую стандартную Java IDE.

В некоторых случаях нам может понадобиться настроить параметры IDE.

Нашим следующим шагом будет сборка проекта:

mvn clean install -DskipTests

После успешной сборки мы можем запустить класс AppServer как Java-приложение из IDE. Это запустит сервер с консолью администратора, прослушивающей порт 8080.

Мы можем перейти по адресу http://127.0.0.1:8080/api/@/ui и увидеть базовый пользовательский интерфейс.

Маршруты, начинающиеся с /@/, используются для консоли администратора, которая является зарезервированным путем в RESTX.

Для входа в консоль администратора мы можем использовать имя пользователя по умолчанию «admin» и пароль, который мы указали при создании приложения.

Прежде чем мы поиграемся с консолью, давайте изучим код и поймем, что сгенерировал мастер.

6. Ресурс RESTX

Маршруты определены в классе \u003cmain_package\u003e.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")));
    }
}

Сразу видно, что RESTX использует аннотации J2EE по умолчанию для безопасности и привязок REST. По большей части он использует собственные аннотации для внедрения зависимостей.

RESTX также поддерживает множество разумных значений по умолчанию для сопоставления параметров метода с запросом.

И, помимо этих стандартных аннотаций, есть @RestxResource, который объявляет его как ресурс, распознаваемый RESTX.

Базовый путь добавляется в файл src/main/webapp/WEB-INF/web.xml. В нашем случае это /api, поэтому мы можем отправить запрос GET на адрес http://localhost:8080/api/message, предполагая надлежащую аутентификацию.

Класс Message — это просто Java-бин, который RESTX сериализует в JSON.

Мы контролируем доступ пользователя, указав аннотацию RolesAllowed с использованием HELLO_ROLE, сгенерированного загрузчиком.

7. Класс модуля

Как отмечалось ранее, RESTX использует стандартные для J2EE аннотации внедрения зависимостей, такие как @Named, и при необходимости изобретает свои собственные, вероятно, беря пример из инфраструктуры Dagger для @Module и @Provides.

Он использует их для создания основного модуля приложения, который, среди прочего, определяет пароль администратора:

@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 определяет класс, который может определять другие компоненты, подобные @Module в Dagger или @Configuration весной.

@Provides предоставляет компонент программно, например @Provides в Dagger или @Bean в Spring.

И, наконец, аннотация @Named используется для указания имени создаваемого компонента.

«AppModule также предоставляет SignatureKey, используемый для подписи содержимого, отправляемого клиентам. Например, при создании сеанса для примера приложения будет установлен файл cookie, подписанный настроенным ключом:

HTTP/1.1 200 OK
...
Set-Cookie: RestxSessionSignature-restx-demo="ySfv8FejvizMMvruGlK3K2hwdb8="; RestxSession-restx-demo="..."
...

И ознакомьтесь с документацией по внедрению фабрики/зависимостей компонентов RESTX для получения дополнительной информации.

8. Класс запуска

И, наконец, класс AppServer используется для запуска приложения как стандартного Java-приложения на встроенном сервере Jetty:

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

Здесь во время разработки используется режим разработки Этап, чтобы включить такие функции, как автоматическая компиляция, которая сокращает цикл обратной связи при разработке.

Мы можем упаковать приложение как файл войны (веб-архив) для развертывания в автономном веб-контейнере J2EE.

Давайте узнаем, как протестировать приложение в следующем разделе.

9. Интеграционное тестирование с использованием спецификаций

Одной из сильных сторон RESTX является концепция «спецификаций». Примерная спецификация будет выглядеть так:

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"}

Тест записывается в структуре Given-When-Then в файле YAML, который в основном определяет, как API должен реагировать (затем) на конкретный запрос (когда) с учетом текущее состояние системы (задано).

Класс HelloResourceSpecTest в src/test/resources будет запускать тесты, описанные в приведенных выше спецификациях:

@RunWith(RestxSpecTestsRunner.class)
@FindSpecsIn("specs/hello")
public class HelloResourceSpecTest {}

Класс RestxSpecTestsRunner — это настраиваемый модуль запуска JUnit. Он содержит настраиваемые правила JUnit для:

    настройки встроенного сервера подготовки состояния системы (в соответствии с данным разделом в спецификациях) отправки указанных запросов и проверки ожидаемых ответов

Аннотация @FindSpecsIn указывает на путь к файлам спецификаций, для которых должны выполняться тесты.

Спецификация помогает писать интеграционные тесты и предоставлять примеры в документации по API. Спецификации также полезны для имитации HTTP-запросов и записи пар запрос/ответ.

10. Ручное тестирование

Мы также можем протестировать вручную через HTTP. Сначала нам нужно войти в систему, и для этого нам нужно хэшировать пароль администратора в консоли RESTX:

hash md5 <clear-text-password>

И затем мы можем передать его в конечную точку /sessions:

curl -b u1 -c u1 -X POST -H "Content-Type: application/json" 
  -d '{"principal":{"name":"admin","passwordHash":"1d528266b85cf052803a57288"}}'
  http://localhost:8080/api/sessions

(Примечание что пользователям Windows необходимо сначала загрузить curl.)

А теперь, если мы используем сеанс как часть нашего запроса /message:

curl -b u1 "http://localhost:8080/api/message?who=restx"

Тогда мы получим что-то вроде этого:

{"message" : "hello admin, it's 09:56:51"}

11. Изучение консоли администратора

Консоль администратора предоставляет полезные ресурсы для управления приложением.

Давайте рассмотрим основные функции, перейдя по адресу http://127.0.0.1:8080/admin/@/ui.

11.1. API Docs

В разделе API docs перечислены все доступные маршруты, включая все параметры:

И мы можем нажать на отдельные маршруты и попробовать их на самой консоли:

11.2. Мониторинг

В разделе «Метрики JVM» показаны метрики приложения с активными сеансами, использованием памяти и дампом потока:

В разделе «Метрики приложения» по умолчанию отслеживаются в основном две категории элементов: компоненты приложения HTTP соответствует HTTP-запросам, обрабатываемым RESTX

    11.3. Статистика

RESTX позволяет пользователю собирать и делиться анонимной статистикой в ​​приложении, чтобы предоставить информацию сообществу RESTX. Мы можем легко отказаться, исключив модуль restx-stats-admin.

Статистика сообщает такие вещи, как базовая ОС и версия JVM:

Поскольку на этой странице отображается конфиденциальная информация, обязательно просмотрите ее параметры конфигурации.

Помимо этого, консоль администратора также может нам помочь:

проверить журналы сервера (Logs) просмотреть обнаруженные ошибки (Errors) проверить переменные среды (Config)

    12. Авторизация

Конечные точки RESTX защищены по умолчанию. Это означает, что если для любой конечной точки:

При вызове без аутентификации по умолчанию возвращается ошибка 401.

@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

Чтобы сделать конечную точку общедоступной, нам нужно использовать аннотацию @PermitAll либо на уровне метода, либо на уровне класса:

Обратите внимание, что на уровне класса все методы являются общедоступными.

@PermitAll 
@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

Кроме того, фреймворк также позволяет указывать роли пользователей с помощью аннотации @RolesAllowed:

«

@RolesAllowed("admin")
@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

«С помощью этой аннотации RESTX проверит, назначена ли аутентифицированному пользователю роль администратора. Если аутентифицированный пользователь без ролей администратора попытается получить доступ к конечной точке, приложение вернет 403 вместо 401.

По умолчанию роли пользователей и учетные данные хранятся в файловой системе в отдельных файлах.

Итак, идентификатор пользователя с зашифрованным паролем хранится в файле /data/credentials.json:

{
    "user1": "$2a$10$iZluUbCseDOvKnoe",
    "user2": "$2a$10$oym3Swr7pScdiCXu"
}

А роли пользователей определены в файле /data/users.json:

[
    {"name":"user1", "roles": ["hello"]},
    {"name":"user2", "roles": []}
]

~~ ~ В примере приложения файлы загружаются в AppModule через класс FileBasedUserRepository:

new FileBasedUserRepository<>(StdUser.class, mapper, 
  new StdUser("admin", ImmutableSet.<String> of("*")), 
  Paths.get("data/users.json"), Paths.get("data/credentials.json"), true)

Класс StdUser содержит пользовательские объекты. Это может быть собственный пользовательский класс, но он должен сериализоваться в JSON.

Конечно, мы можем использовать другую реализацию UserRepository, например ту, которая обращается к базе данных.

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

В этом руководстве представлен обзор легковесной среды RESTX на основе Java.

Фреймворк все еще находится в разработке, и при его использовании могут быть некоторые шероховатости. Ознакомьтесь с официальной документацией для более подробной информации.

Образец загрузочного приложения доступен в нашем репозитории GitHub.