Въведение в RESTX

1. Общ преглед

В този урок ще направим обиколка на леката Java REST рамка RESTX.

2. Характеристики

Изграждането на RESTful API е доста лесно с рамката RESTX. Той има всички настройки по подразбиране, които можем да очакваме от REST рамка, като обслужване и консумиране на JSON, параметри на заявка и път, механизми за маршрутизиране и филтриране, статистика за използването и мониторинг.

RESTX също се предлага с интуитивна административна уеб конзола и инсталатор на команден ред за лесно зареждане.

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

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

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

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

4. Инсталиране на Core Plugins

Сега е време да инсталирате основните плъгини, за да можете да създадете приложение от самата обвивка.

В RESTX черупката, нека изпълним следната команда:

shell install

След това ще ни подкани да изберем приставките за инсталиране. Трябва да изберем номера, който сочи към io.restx: restx-core-shell . Черупката автоматично ще се рестартира, след като инсталацията завърши.

5. Bootstrap на Shell App

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

Започваме с изпълнението на следната команда върху черупката:

app new

Тази команда ще задейства съветника. Тогава можем или да използваме опциите по подразбиране, или да ги променим според нашите изисквания:

Тъй като избрахме да генерираме pom.xml, проектът може лесно да бъде импортиран във всяка стандартна Java IDE.

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

Следващата ни стъпка ще бъде изграждането на проекта:

mvn clean install -DskipTests

След като компилацията е успешна, можем да стартираме класа AppServer като Java приложение от IDE . Това ще стартира сървъра с администраторската конзола, слуша на порт 8080.

Можем да прегледаме //127.0.0.1:8080/api/@/ui и да видим основния потребителски интерфейс.

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

За да влезем в администраторската конзола, можем да използваме потребителското име по подразбиране „admin и паролата, която сме предоставили при създаването на приложението.

Преди да си поиграем с конзолата, нека изследваме кода и ще разберем какво е генерирал съветникът.

6. Ресурс RESTX

Маршрутите са дефинирани в < 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"))); } }

Веднага става ясно, че RESTX използва анотации по подразбиране J2EE за сигурност и REST обвързвания. В по-голямата си част той използва свои собствени анотации за инжектиране на зависимост.

RESTX също поддържа много разумни настройки по подразбиране за картографиране на параметрите на метода към заявката.

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

Основният път е добавен в src / main / webapp / WEB-INF / web.xml. В нашия случай това е / api , така че можем да изпратим GET заявка до // localhost: 8080 / api / message , като приемем правилното удостоверяване.

Класът Съобщение е само Java компонент, който RESTX сериализира в JSON.

Ние контролираме потребителския достъп, като посочваме анотацията RolesAllowed, използвайки HELLO_ROLE, който е генериран от bootstrapper.

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 през Spring.

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

И накрая, анотацията @Named се използва, за да посочи името на произвеждания компонент.

AppModule също така предоставя SignatureKey, използван за подписване на съдържание, изпратено до клиентите. Докато създавате сесията за примерното приложение, например, това ще зададе бисквитка, подписана с конфигурирания ключ:

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

The test is written in a Given-When-Then structure within a YAML file which basically defines how the API should respond (then) to a specific request (when) given a current state of the system (given).

The HelloResourceSpecTest class in src/test/resources will trigger the tests written in the specs above:

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

The RestxSpecTestsRunner class is a custom JUnit runner. It contains custom JUnit rules to:

  • set up an embedded server
  • prepare the state of the system (as per the given section in the specs)
  • issue the specified requests, and
  • verify the expected responses

The @FindSpecsIn annotation points to the path of the spec files against which the tests should be run.

The spec helps to write integration tests and provide examples in the API docs. Specs are also useful to mock HTTP requests and record request/response pairs.

10. Manual Testing

We can also test manually over HTTP. We first need to log in, and to do this, we need to hash the admin password in the RESTX console:

hash md5 

And then we can pass that to the /sessions endpoint:

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

(Note that Windows users need to download curl first.)

And now, if we use the session as part of our /message request:

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

Then we'll get something like this:

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

11. Exploring the Admin Console

The admin console provides useful resources to control the app.

Let's take a look at the key features by browsing to //127.0.0.1:8080/admin/@/ui.

11.1. API Docs

The API docs section lists all available routes including all the options:

And we can click on individual routes and try them out on the console itself:

11.2. Monitoring

The JVM Metrics section shows the application metrics with active sessions, memory usage, and thread dump:

Under Application Metrics we have mainly two categories of elements monitored by default:

  • BUILD corresponds to the instantiation of the application components
  • HTTP corresponds to HTTP requests handled by RESTX

11.3. Stats

RESTX lets the user choose to collect and share anonymous stats on the application to give information to the RESTX community. We can easily opt out by excluding the restx-stats-admin module.

The stats report things like the underlying OS and the JVM version:

Because this page shows sensitive information,make sure to review its configuration options.

Apart from these, the admin console can also help us:

  • check the server logs (Logs)
  • view the errors encountered (Errors)
  • check the environment variables (Config)

12. Authorization

RESTX endpoints are secured by default. That means if for any endpoint:

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

When called without authentication will return a 401 by default.

To make an endpoint public, we need to use the @PermitAll annotation either at the method or class level:

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

Note that at the class level, all methods are public.

Further, the framework also allows specifying user roles using the @RolesAllowed annotation:

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

With this annotation, RESTX will verify if the authenticated user also has an admin role assigned. In case an authenticated user without admin roles tries to access the endpoint, the application will return a 403 instead of a 401.

By default, the user roles and credentials are stored on the filesystem, in separate files.

So, the user id with the encrypted password is stored under /data/credentials.json file:

{ "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. of("*")), Paths.get("data/users.json"), Paths.get("data/credentials.json"), true)

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

Можем, разбира се, да използваме различна реализация на UserRepository , като тази, която попада в база данни.

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

Този урок даде преглед на леката RESTX рамка, базирана на Java.

Рамката все още се разработва и може да има някои груби ръбове, които я използват. Вижте официалната документация за повече подробности.

Примерното приложение за зареждане е достъпно в нашето хранилище GitHub.