You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ib...@apache.org on 2022/03/04 06:41:23 UTC

[ignite-3] branch main updated: IGNITE-16498 Add ability to add handlers to RestModule from other Ignite modules (#690)

This is an automated email from the ASF dual-hosted git repository.

ibessonov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new ed519fb  IGNITE-16498 Add ability to add handlers to RestModule from other Ignite modules (#690)
ed519fb is described below

commit ed519fb2fa2a89e11a8ab7fad3069f7e1f7d74b3
Author: Roman Puchkovskiy <ro...@gmail.com>
AuthorDate: Fri Mar 4 10:41:15 2022 +0400

    IGNITE-16498 Add ability to add handlers to RestModule from other Ignite modules (#690)
---
 modules/api/pom.xml                                |   5 -
 modules/configuration/pom.xml                      |  10 ++
 .../rest/ConfigurationHttpHandlers.java}           | 168 ++++-----------------
 .../presentation/ConfigurationPresentation.java    |   2 +-
 .../rest/presentation/hocon/HoconPresentation.java |   4 +-
 .../rest/presentation/hocon/package-info.java      |   2 +-
 .../rest/presentation/package-info.java            |   2 +-
 .../ConfigurationPresentationTest.java             |   4 +-
 modules/page-memory/pom.xml                        |   5 +
 modules/{api => rest-api}/pom.xml                  |  57 +++----
 .../ignite/internal/rest/api}/ErrorResult.java     |   2 +-
 .../ignite/internal/rest/api}/RequestHandler.java  |   4 +-
 .../internal/rest/api}/RestApiHttpRequest.java     |   2 +-
 .../internal/rest/api}/RestApiHttpResponse.java    |   2 +-
 .../internal/rest/api/RestHandlersRegister.java}   |  16 +-
 .../apache/ignite/internal/rest/api}/Route.java    |   4 +-
 .../apache/ignite/internal/rest/api/Routes.java    |  83 ++++++++++
 .../rest/api}/RestApiHttpResponseTest.java         |   3 +-
 modules/rest/pom.xml                               |   5 +
 .../apache/ignite/internal/rest/RestComponent.java | 149 ++++++++++++++++++
 .../ignite/internal/rest/netty/RestApiHandler.java |   1 +
 .../apache/ignite/internal/rest/routes/Router.java | 102 +------------
 .../ignite/internal/rest/routes/SimpleRouter.java  |  71 +++++++++
 .../ignite/internal/rest/routes/RouteTest.java     |   2 +
 .../org/apache/ignite/internal/app/IgniteImpl.java |  15 +-
 .../CoreDistributedConfigurationModule.java        |   4 +-
 .../CoreLocalConfigurationModule.java              |   4 +-
 ...nite.internal.configuration.ConfigurationModule |   4 +-
 .../CoreDistributedConfigurationModuleTest.java    |   3 +-
 .../CoreLocalConfigurationModuleTest.java          |   3 +-
 parent/pom.xml                                     |   6 +
 pom.xml                                            |   1 +
 32 files changed, 436 insertions(+), 309 deletions(-)

diff --git a/modules/api/pom.xml b/modules/api/pom.xml
index 833b90f..86594f8 100644
--- a/modules/api/pom.xml
+++ b/modules/api/pom.xml
@@ -38,11 +38,6 @@
             <artifactId>ignite-configuration-api</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-configuration</artifactId>
-        </dependency>
-
         <!-- 3rd party dependencies -->
         <dependency>
             <groupId>org.jetbrains</groupId>
diff --git a/modules/configuration/pom.xml b/modules/configuration/pom.xml
index c8a84b8..1063894 100644
--- a/modules/configuration/pom.xml
+++ b/modules/configuration/pom.xml
@@ -43,6 +43,16 @@
             <artifactId>ignite-configuration-api</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-rest-api</artifactId>
+        </dependency>
+
         <!-- 3rd party dependencies -->
         <dependency>
             <groupId>com.typesafe</groupId>
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestModule.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/ConfigurationHttpHandlers.java
similarity index 51%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/RestModule.java
rename to modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/ConfigurationHttpHandlers.java
index e70dc0a..09e9dda 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestModule.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/ConfigurationHttpHandlers.java
@@ -15,103 +15,62 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest;
+package org.apache.ignite.internal.configuration.rest;
 
 import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON;
 import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
 
-import io.netty.bootstrap.ServerBootstrap;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
-import io.netty.handler.logging.LogLevel;
-import io.netty.handler.logging.LoggingHandler;
-import java.net.BindException;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
-import org.apache.ignite.configuration.schemas.rest.RestConfiguration;
-import org.apache.ignite.configuration.schemas.rest.RestView;
 import org.apache.ignite.configuration.validation.ConfigurationValidationException;
 import org.apache.ignite.internal.configuration.ConfigurationManager;
-import org.apache.ignite.internal.configuration.ConfigurationRegistry;
-import org.apache.ignite.internal.manager.IgniteComponent;
-import org.apache.ignite.internal.rest.netty.RestApiHttpRequest;
-import org.apache.ignite.internal.rest.netty.RestApiHttpResponse;
-import org.apache.ignite.internal.rest.netty.RestApiInitializer;
-import org.apache.ignite.internal.rest.presentation.ConfigurationPresentation;
-import org.apache.ignite.internal.rest.presentation.hocon.HoconPresentation;
-import org.apache.ignite.internal.rest.routes.Router;
+import org.apache.ignite.internal.configuration.rest.presentation.ConfigurationPresentation;
+import org.apache.ignite.internal.configuration.rest.presentation.hocon.HoconPresentation;
+import org.apache.ignite.internal.rest.api.ErrorResult;
+import org.apache.ignite.internal.rest.api.RestApiHttpRequest;
+import org.apache.ignite.internal.rest.api.RestApiHttpResponse;
+import org.apache.ignite.internal.rest.api.RestHandlersRegister;
+import org.apache.ignite.internal.rest.api.Routes;
 import org.apache.ignite.lang.IgniteException;
-import org.apache.ignite.lang.IgniteLogger;
-import org.apache.ignite.network.NettyBootstrapFactory;
 
 /**
- * Rest module is responsible for starting a REST endpoints for accessing and managing configuration.
- *
- * <p>It is started on port 10300 by default but it is possible to change this in configuration itself. Refer to default config file in
- * resources for the example.
+ * HTTP handlers for configuration-related REST endpoints.
  */
-public class RestModule implements IgniteComponent {
-    /** Default port. */
-    public static final int DFLT_PORT = 10300;
-
-    /** Node configuration route. */
+public class ConfigurationHttpHandlers {
+    /**
+     * Node configuration route.
+     */
     private static final String NODE_CFG_URL = "/management/v1/configuration/node/";
 
-    /** Cluster configuration route. */
+    /**
+     * Cluster configuration route.
+     */
     private static final String CLUSTER_CFG_URL = "/management/v1/configuration/cluster/";
 
-    /** Path parameter. */
-    private static final String PATH_PARAM = "selector";
-
-    /** Ignite logger. */
-    private final IgniteLogger log = IgniteLogger.forClass(RestModule.class);
-
-    /** Node configuration register. */
-    private final ConfigurationRegistry nodeCfgRegistry;
-
-    /** Presentation of node configuration. */
-    private final ConfigurationPresentation<String> nodeCfgPresentation;
-
-    /** Presentation of cluster configuration. */
-    private final ConfigurationPresentation<String> clusterCfgPresentation;
-
-    /** Netty bootstrap factory. */
-    private final NettyBootstrapFactory bootstrapFactory;
-
-    /** Netty channel. */
-    private volatile Channel channel;
-
     /**
-     * Creates a new instance of REST module.
-     *
-     * @param nodeCfgMgr       Node configuration manager.
-     * @param clusterCfgMgr    Cluster configuration manager.
-     * @param bootstrapFactory Netty bootstrap factory.
+     * Path parameter.
      */
-    public RestModule(
-            ConfigurationManager nodeCfgMgr,
-            ConfigurationManager clusterCfgMgr,
-            NettyBootstrapFactory bootstrapFactory) {
-        nodeCfgRegistry = nodeCfgMgr.configurationRegistry();
+    private static final String PATH_PARAM = "selector";
 
-        nodeCfgPresentation = new HoconPresentation(nodeCfgMgr.configurationRegistry());
-        clusterCfgPresentation = new HoconPresentation(clusterCfgMgr.configurationRegistry());
+    private final ConfigurationManager nodeConfigurationManager;
+    private final ConfigurationManager clusterConfigurationManager;
 
-        this.bootstrapFactory = bootstrapFactory;
+    public ConfigurationHttpHandlers(ConfigurationManager nodeConfigurationManager, ConfigurationManager clusterConfigurationManager) {
+        this.nodeConfigurationManager = nodeConfigurationManager;
+        this.clusterConfigurationManager = clusterConfigurationManager;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public void start() {
-        if (channel != null) {
-            throw new IgniteException("RestModule is already started.");
-        }
+    public void registerHandlers(RestHandlersRegister register) {
+        register.registerHandlers(this::registerOn);
+    }
 
-        var router = new Router();
+    private void registerOn(Routes routes) {
+        var nodeCfgPresentation = new HoconPresentation(nodeConfigurationManager.configurationRegistry());
+        var clusterCfgPresentation = new HoconPresentation(clusterConfigurationManager.configurationRegistry());
 
-        router
+        routes
                 .get(
                         NODE_CFG_URL,
                         (req, resp) -> {
@@ -138,77 +97,14 @@ public class RestModule implements IgniteComponent {
                 )
                 .patch(
                         NODE_CFG_URL,
-                        APPLICATION_JSON,
+                        APPLICATION_JSON.toString(),
                         (req, resp) -> handleUpdate(req, resp, nodeCfgPresentation)
                 )
                 .patch(
                         CLUSTER_CFG_URL,
-                        APPLICATION_JSON,
+                        APPLICATION_JSON.toString(),
                         (req, resp) -> handleUpdate(req, resp, clusterCfgPresentation)
                 );
-
-        channel = startRestEndpoint(router).channel();
-    }
-
-    /**
-     * Start endpoint.
-     *
-     * @param router Dispatcher of http requests.
-     * @return Future which will be notified when this channel is closed.
-     * @throws RuntimeException if this module cannot be bound to a port.
-     */
-    private ChannelFuture startRestEndpoint(Router router) {
-        RestView restConfigurationView = nodeCfgRegistry.getConfiguration(RestConfiguration.KEY).value();
-
-        int desiredPort = restConfigurationView.port();
-        int portRange = restConfigurationView.portRange();
-
-        int port = 0;
-
-        Channel ch = null;
-
-        var hnd = new RestApiInitializer(router);
-
-        ServerBootstrap b = bootstrapFactory.createServerBootstrap()
-                .handler(new LoggingHandler(LogLevel.INFO))
-                .childHandler(hnd);
-
-        for (int portCandidate = desiredPort; portCandidate <= desiredPort + portRange; portCandidate++) {
-            ChannelFuture bindRes = b.bind(portCandidate).awaitUninterruptibly();
-
-            if (bindRes.isSuccess()) {
-                ch = bindRes.channel();
-                port = portCandidate;
-                break;
-            } else if (!(bindRes.cause() instanceof BindException)) {
-                throw new RuntimeException(bindRes.cause());
-            }
-        }
-
-        if (ch == null) {
-            String msg = "Cannot start REST endpoint. "
-                    + "All ports in range [" + desiredPort + ", " + (desiredPort + portRange) + "] are in use.";
-
-            log.error(msg);
-
-            throw new RuntimeException(msg);
-        }
-
-        if (log.isInfoEnabled()) {
-            log.info("REST protocol started successfully on port " + port);
-        }
-
-        return ch.closeFuture();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void stop() throws Exception {
-        if (channel != null) {
-            channel.close().await();
-
-            channel = null;
-        }
     }
 
     /**
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/ConfigurationPresentation.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/ConfigurationPresentation.java
similarity index 97%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/ConfigurationPresentation.java
rename to modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/ConfigurationPresentation.java
index 5bdb920..d053155 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/ConfigurationPresentation.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/ConfigurationPresentation.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.presentation;
+package org.apache.ignite.internal.configuration.rest.presentation;
 
 import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.configuration.validation.ConfigurationValidationException;
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/hocon/HoconPresentation.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/hocon/HoconPresentation.java
similarity index 95%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/hocon/HoconPresentation.java
rename to modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/hocon/HoconPresentation.java
index 065c52b..5025ffb 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/hocon/HoconPresentation.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/hocon/HoconPresentation.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.presentation.hocon;
+package org.apache.ignite.internal.configuration.rest.presentation.hocon;
 
 import static com.typesafe.config.ConfigFactory.parseString;
 import static com.typesafe.config.ConfigRenderOptions.concise;
@@ -30,7 +30,7 @@ import org.apache.ignite.configuration.ConfigurationChangeException;
 import org.apache.ignite.configuration.validation.ConfigurationValidationException;
 import org.apache.ignite.internal.configuration.ConfigurationRegistry;
 import org.apache.ignite.internal.configuration.hocon.HoconConverter;
-import org.apache.ignite.internal.rest.presentation.ConfigurationPresentation;
+import org.apache.ignite.internal.configuration.rest.presentation.ConfigurationPresentation;
 import org.apache.ignite.lang.IgniteException;
 import org.jetbrains.annotations.Nullable;
 
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/hocon/package-info.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/hocon/package-info.java
similarity index 92%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/hocon/package-info.java
rename to modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/hocon/package-info.java
index 3c0dffa..a3e1868 100755
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/hocon/package-info.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/hocon/package-info.java
@@ -19,4 +19,4 @@
  * This package contains classes related to HOCON representation.
  */
 
-package org.apache.ignite.internal.rest.presentation.hocon;
+package org.apache.ignite.internal.configuration.rest.presentation.hocon;
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/package-info.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/package-info.java
similarity index 93%
copy from modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/package-info.java
copy to modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/package-info.java
index 7aa8c91..98b9534 100755
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/package-info.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/rest/presentation/package-info.java
@@ -19,4 +19,4 @@
  * Contains a base interface that provides the ability to convert representation to other formats.
  */
 
-package org.apache.ignite.internal.rest.presentation;
+package org.apache.ignite.internal.configuration.rest.presentation;
diff --git a/modules/rest/src/test/java/org/apache/ignite/internal/rest/presentation/ConfigurationPresentationTest.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/rest/presentation/ConfigurationPresentationTest.java
similarity index 97%
rename from modules/rest/src/test/java/org/apache/ignite/internal/rest/presentation/ConfigurationPresentationTest.java
rename to modules/configuration/src/test/java/org/apache/ignite/internal/configuration/rest/presentation/ConfigurationPresentationTest.java
index 375a859..1cc8e7e 100644
--- a/modules/rest/src/test/java/org/apache/ignite/internal/rest/presentation/ConfigurationPresentationTest.java
+++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/rest/presentation/ConfigurationPresentationTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.presentation;
+package org.apache.ignite.internal.configuration.rest.presentation;
 
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
@@ -42,8 +42,8 @@ import org.apache.ignite.configuration.validation.ValidationContext;
 import org.apache.ignite.configuration.validation.ValidationIssue;
 import org.apache.ignite.configuration.validation.Validator;
 import org.apache.ignite.internal.configuration.ConfigurationRegistry;
+import org.apache.ignite.internal.configuration.rest.presentation.hocon.HoconPresentation;
 import org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
-import org.apache.ignite.internal.rest.presentation.hocon.HoconPresentation;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/modules/page-memory/pom.xml b/modules/page-memory/pom.xml
index f48349d..9c11459 100644
--- a/modules/page-memory/pom.xml
+++ b/modules/page-memory/pom.xml
@@ -43,6 +43,11 @@
             <artifactId>ignite-core</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-configuration</artifactId>
+        </dependency>
+
         <!-- Test dependencies -->
         <dependency>
             <groupId>org.junit.jupiter</groupId>
diff --git a/modules/api/pom.xml b/modules/rest-api/pom.xml
similarity index 61%
copy from modules/api/pom.xml
copy to modules/rest-api/pom.xml
index 833b90f..08a4421 100644
--- a/modules/api/pom.xml
+++ b/modules/rest-api/pom.xml
@@ -29,21 +29,21 @@
         <relativePath>../../parent/pom.xml</relativePath>
     </parent>
 
-    <artifactId>ignite-api</artifactId>
+    <artifactId>ignite-rest-api</artifactId>
     <version>3.0.0-SNAPSHOT</version>
 
     <dependencies>
+        <!-- 3rd party dependencies -->
         <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-configuration-api</artifactId>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
         </dependency>
 
         <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-configuration</artifactId>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec-http</artifactId>
         </dependency>
 
-        <!-- 3rd party dependencies -->
         <dependency>
             <groupId>org.jetbrains</groupId>
             <artifactId>annotations</artifactId>
@@ -51,46 +51,37 @@
 
         <!-- Test dependencies -->
         <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-engine</artifactId>
+            <artifactId>junit-jupiter-api</artifactId>
             <scope>test</scope>
         </dependency>
 
         <dependency>
-            <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest</artifactId>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
             <scope>test</scope>
         </dependency>
 
+        <!-- Logging in tests -->
         <dependency>
-            <groupId>com.github.npathai</groupId>
-            <artifactId>hamcrest-optional</artifactId>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
 
     <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.apache.ignite</groupId>
-                        <artifactId>ignite-configuration-annotation-processor</artifactId>
-                        <version>${project.version}</version>
-                    </dependency>
-                </dependencies>
-                <configuration>
-                    <annotationProcessorPaths>
-                        <path>
-                            <groupId>org.apache.ignite</groupId>
-                            <artifactId>ignite-configuration-annotation-processor</artifactId>
-                            <version>${project.version}</version>
-                        </path>
-                    </annotationProcessorPaths>
-                </configuration>
-            </plugin>
-        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
     </build>
 </project>
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/ErrorResult.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/ErrorResult.java
similarity index 97%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/ErrorResult.java
rename to modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/ErrorResult.java
index becbb9a..41b400a 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/ErrorResult.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/ErrorResult.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest;
+package org.apache.ignite.internal.rest.api;
 
 /**
  * Error result represent a tuple of error type and user-friendly error message.
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/RequestHandler.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RequestHandler.java
similarity index 89%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/RequestHandler.java
rename to modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RequestHandler.java
index 8d2ffde..22d0d94 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/RequestHandler.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RequestHandler.java
@@ -15,11 +15,9 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.routes;
+package org.apache.ignite.internal.rest.api;
 
 import java.util.concurrent.CompletableFuture;
-import org.apache.ignite.internal.rest.netty.RestApiHttpRequest;
-import org.apache.ignite.internal.rest.netty.RestApiHttpResponse;
 
 /**
  * Interface for defining REST API request handlers.
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHttpRequest.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestApiHttpRequest.java
similarity index 97%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHttpRequest.java
rename to modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestApiHttpRequest.java
index d52cc6a..af49252 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHttpRequest.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestApiHttpRequest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.netty;
+package org.apache.ignite.internal.rest.api;
 
 import io.netty.handler.codec.http.FullHttpRequest;
 import java.util.Collections;
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHttpResponse.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestApiHttpResponse.java
similarity index 98%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHttpResponse.java
rename to modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestApiHttpResponse.java
index 35a2f10..daa8ead 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHttpResponse.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestApiHttpResponse.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.netty;
+package org.apache.ignite.internal.rest.api;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
 import com.fasterxml.jackson.annotation.PropertyAccessor;
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/package-info.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestHandlersRegister.java
old mode 100755
new mode 100644
similarity index 70%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/package-info.java
rename to modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestHandlersRegister.java
index 7aa8c91..c55e7d6
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/presentation/package-info.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/RestHandlersRegister.java
@@ -15,8 +15,18 @@
  * limitations under the License.
  */
 
+package org.apache.ignite.internal.rest.api;
+
+import java.util.function.Consumer;
+
 /**
- * Contains a base interface that provides the ability to convert representation to other formats.
+ * Register for REST handlers.
  */
-
-package org.apache.ignite.internal.rest.presentation;
+public interface RestHandlersRegister {
+    /**
+     * Registers handlers on the provided {@link Routes}.
+     *
+     * @param registerAction registration action
+     */
+    void registerHandlers(Consumer<Routes> registerAction);
+}
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/Route.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/Route.java
similarity index 96%
rename from modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/Route.java
rename to modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/Route.java
index 442d491..90c3b47 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/Route.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/Route.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.routes;
+package org.apache.ignite.internal.rest.api;
 
 import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.codec.http.HttpHeaderNames;
@@ -26,8 +26,6 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
-import org.apache.ignite.internal.rest.netty.RestApiHttpRequest;
-import org.apache.ignite.internal.rest.netty.RestApiHttpResponse;
 import org.jetbrains.annotations.Nullable;
 
 /**
diff --git a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/Routes.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/Routes.java
new file mode 100644
index 0000000..16a1b9b
--- /dev/null
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/Routes.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.rest.api;
+
+import io.netty.handler.codec.http.HttpMethod;
+
+/**
+ * Allows to configure routes to REST handlers mapping.
+ */
+public interface Routes {
+    /**
+     * Adds the route to the router chain.
+     *
+     * @param route Route
+     */
+    void addRoute(Route route);
+
+    /**
+     * Adds a GET handler.
+     *
+     * @param route      Route.
+     * @param acceptType Accept type.
+     * @param hnd        Actual handler of the request.
+     * @return Router
+     */
+    default Routes get(String route, String acceptType, RequestHandler hnd) {
+        addRoute(new Route(route, HttpMethod.GET, acceptType, hnd));
+        return this;
+    }
+
+    /**
+     * Adds a GET handler.
+     *
+     * @param route Route.
+     * @param hnd   Actual handler of the request.
+     * @return Router
+     */
+    default Routes get(String route, RequestHandler hnd) {
+        addRoute(new Route(route, HttpMethod.GET, null, hnd));
+        return this;
+    }
+
+    /**
+     * Adds a PUT handler.
+     *
+     * @param route      Route.
+     * @param acceptType Accept type.
+     * @param hnd        Actual handler of the request.
+     * @return Router
+     */
+    default Routes put(String route, String acceptType, RequestHandler hnd) {
+        addRoute(new Route(route, HttpMethod.PUT, acceptType, hnd));
+        return this;
+    }
+
+    /**
+     * Adds a PATCH handler.
+     *
+     * @param route      Route.
+     * @param acceptType Accept type.
+     * @param hnd        Actual handler of the request.
+     * @return Router
+     */
+    default Routes patch(String route, String acceptType, RequestHandler hnd) {
+        addRoute(new Route(route, HttpMethod.PATCH, acceptType, hnd));
+        return this;
+    }
+}
diff --git a/modules/rest/src/test/java/org/apache/ignite/internal/rest/netty/RestApiHttpResponseTest.java b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/api/RestApiHttpResponseTest.java
similarity index 95%
rename from modules/rest/src/test/java/org/apache/ignite/internal/rest/netty/RestApiHttpResponseTest.java
rename to modules/rest-api/src/test/java/org/apache/ignite/internal/rest/api/RestApiHttpResponseTest.java
index 3b41c1a..2419099 100644
--- a/modules/rest/src/test/java/org/apache/ignite/internal/rest/netty/RestApiHttpResponseTest.java
+++ b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/api/RestApiHttpResponseTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.rest.netty;
+package org.apache.ignite.internal.rest.api;
 
 import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
 import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON;
@@ -26,7 +26,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import io.netty.handler.codec.http.DefaultHttpResponse;
 import io.netty.handler.codec.http.HttpVersion;
 import java.util.Map;
-import org.apache.ignite.internal.rest.ErrorResult;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/modules/rest/pom.xml b/modules/rest/pom.xml
index 8ac7870..cd924ee 100644
--- a/modules/rest/pom.xml
+++ b/modules/rest/pom.xml
@@ -35,6 +35,11 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-rest-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
             <artifactId>ignite-configuration</artifactId>
         </dependency>
 
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
new file mode 100644
index 0000000..247061c
--- /dev/null
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.rest;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import java.net.BindException;
+import java.util.function.Consumer;
+import org.apache.ignite.configuration.schemas.rest.RestConfiguration;
+import org.apache.ignite.configuration.schemas.rest.RestView;
+import org.apache.ignite.internal.configuration.ConfigurationManager;
+import org.apache.ignite.internal.configuration.ConfigurationRegistry;
+import org.apache.ignite.internal.manager.IgniteComponent;
+import org.apache.ignite.internal.rest.api.RestHandlersRegister;
+import org.apache.ignite.internal.rest.api.Routes;
+import org.apache.ignite.internal.rest.netty.RestApiInitializer;
+import org.apache.ignite.internal.rest.routes.Router;
+import org.apache.ignite.internal.rest.routes.SimpleRouter;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.lang.IgniteLogger;
+import org.apache.ignite.network.NettyBootstrapFactory;
+
+/**
+ * Rest component is responsible for starting REST endpoints.
+ *
+ * <p>It is started on port 10300 by default, but it is possible to change this in configuration itself. Refer to default config file in
+ * resources for the example.
+ */
+public class RestComponent implements RestHandlersRegister, IgniteComponent {
+    /** Ignite logger. */
+    private final IgniteLogger log = IgniteLogger.forClass(RestComponent.class);
+
+    /** Node configuration register. */
+    private final ConfigurationRegistry nodeCfgRegistry;
+
+    /** Netty bootstrap factory. */
+    private final NettyBootstrapFactory bootstrapFactory;
+
+    private final SimpleRouter router = new SimpleRouter();
+
+    /** Netty channel. */
+    private volatile Channel channel;
+
+    /**
+     * Creates a new instance of REST module.
+     *
+     * @param nodeCfgMgr       Node configuration manager.
+     * @param bootstrapFactory Netty bootstrap factory.
+     */
+    public RestComponent(ConfigurationManager nodeCfgMgr, NettyBootstrapFactory bootstrapFactory) {
+        nodeCfgRegistry = nodeCfgMgr.configurationRegistry();
+
+        this.bootstrapFactory = bootstrapFactory;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void registerHandlers(Consumer<Routes> registerAction) {
+        registerAction.accept(router);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void start() {
+        if (channel != null) {
+            throw new IgniteException("RestModule is already started.");
+        }
+
+        channel = startRestEndpoint(router).channel();
+    }
+
+    /**
+     * Start endpoint.
+     *
+     * @param router Dispatcher of http requests.
+     * @return Future which will be notified when this channel is closed.
+     * @throws RuntimeException if this module cannot be bound to a port.
+     */
+    private ChannelFuture startRestEndpoint(Router router) {
+        RestView restConfigurationView = nodeCfgRegistry.getConfiguration(RestConfiguration.KEY).value();
+
+        int desiredPort = restConfigurationView.port();
+        int portRange = restConfigurationView.portRange();
+
+        int port = 0;
+        Channel ch = null;
+
+        ServerBootstrap bootstrap = bootstrapFactory.createServerBootstrap()
+                .handler(new LoggingHandler(LogLevel.INFO))
+                .childHandler(new RestApiInitializer(router));
+
+        for (int portCandidate = desiredPort; portCandidate <= desiredPort + portRange; portCandidate++) {
+            ChannelFuture bindRes = bootstrap.bind(portCandidate).awaitUninterruptibly();
+
+            if (bindRes.isSuccess()) {
+                ch = bindRes.channel();
+                port = portCandidate;
+                break;
+            } else if (!(bindRes.cause() instanceof BindException)) {
+                throw new RuntimeException(bindRes.cause());
+            }
+        }
+
+        if (ch == null) {
+            String msg = "Cannot start REST endpoint. "
+                    + "All ports in range [" + desiredPort + ", " + (desiredPort + portRange) + "] are in use.";
+
+            log.error(msg);
+
+            throw new RuntimeException(msg);
+        }
+
+        if (log.isInfoEnabled()) {
+            log.info("REST protocol started successfully on port " + port);
+        }
+
+        return ch.closeFuture();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void stop() throws Exception {
+        // TODO: IGNITE-16636 Use busy-lock approach to guard stopping RestComponent
+
+        if (channel != null) {
+            channel.close().await();
+
+            channel = null;
+        }
+    }
+}
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHandler.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHandler.java
index 9b29db0..a392ec2 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHandler.java
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/netty/RestApiHandler.java
@@ -39,6 +39,7 @@ import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.HttpUtil;
 import io.netty.handler.codec.http.HttpVersion;
 import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.internal.rest.api.RestApiHttpResponse;
 import org.apache.ignite.internal.rest.routes.Router;
 import org.apache.ignite.lang.IgniteLogger;
 
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/Router.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/Router.java
index 473f96d..6f3f4af 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/Router.java
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/Router.java
@@ -17,113 +17,19 @@
 
 package org.apache.ignite.internal.rest.routes;
 
-import io.netty.handler.codec.http.HttpMethod;
 import io.netty.handler.codec.http.HttpRequest;
-import io.netty.util.AsciiString;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Optional;
+import org.apache.ignite.internal.rest.api.Route;
 
 /**
  * Dispatcher of http requests.
- *
- * <p>Example:
- * <pre>
- * {@code
- * var router = new Router();
- * router.get("/user", (req, resp) -> {
- *     resp.status(HttpResponseStatus.OK);
- * });
- * }
- * </pre>
  */
-public class Router {
-    /** Routes. */
-    private final List<Route> routes;
-
-    /**
-     * Creates a new router with the given list of {@code routes}.
-     *
-     * @param routes Routes.
-     */
-    public Router(List<Route> routes) {
-        this.routes = routes;
-    }
-
-    /**
-     * Creates a new empty router.
-     */
-    public Router() {
-        routes = new ArrayList<>();
-    }
-
-    /**
-     * GET query helper.
-     *
-     * @param route      Route.
-     * @param acceptType Accept type.
-     * @param hnd        Actual handler of the request.
-     * @return Router
-     */
-    public Router get(String route, AsciiString acceptType, RequestHandler hnd) {
-        addRoute(new Route(route, HttpMethod.GET, acceptType.toString(), hnd));
-        return this;
-    }
-
-    /**
-     * GET query helper.
-     *
-     * @param route Route.
-     * @param hnd   Actual handler of the request.
-     * @return Router
-     */
-    public Router get(String route, RequestHandler hnd) {
-        addRoute(new Route(route, HttpMethod.GET, null, hnd));
-        return this;
-    }
-
-    /**
-     * PUT query helper.
-     *
-     * @param route      Route.
-     * @param acceptType Accept type.
-     * @param hnd        Actual handler of the request.
-     * @return Router
-     */
-    public Router put(String route, AsciiString acceptType, RequestHandler hnd) {
-        addRoute(new Route(route, HttpMethod.PUT, acceptType.toString(), hnd));
-        return this;
-    }
-
-    /**
-     * Defines a PATCH route.
-     *
-     * @param route      Route.
-     * @param acceptType Accept type.
-     * @param hnd        Actual handler of the request.
-     * @return Router
-     */
-    public Router patch(String route, AsciiString acceptType, RequestHandler hnd) {
-        addRoute(new Route(route, HttpMethod.PATCH, acceptType.toString(), hnd));
-        return this;
-    }
-
-    /**
-     * Adds the route to router chain.
-     *
-     * @param route Route
-     */
-    public void addRoute(Route route) {
-        routes.add(route);
-    }
-
+public interface Router {
     /**
      * Finds the route by request.
      *
      * @param req Request.
-     * @return Route if founded.
+     * @return Route if found.
      */
-    public Optional<Route> route(HttpRequest req) {
-        return routes.stream().filter(r -> r.match(req)).findFirst();
-    }
+    Optional<Route> route(HttpRequest req);
 }
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/SimpleRouter.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/SimpleRouter.java
new file mode 100644
index 0000000..c534085
--- /dev/null
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/routes/SimpleRouter.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.rest.routes;
+
+import io.netty.handler.codec.http.HttpRequest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.apache.ignite.internal.rest.api.Route;
+import org.apache.ignite.internal.rest.api.Routes;
+
+/**
+ * Dispatcher of http requests.
+ *
+ * <p>Example:
+ * <pre>
+ * {@code
+ * var router = new SimpleRouter();
+ * router.get("/user", (req, resp) -> {
+ *     resp.status(HttpResponseStatus.OK);
+ * });
+ * }
+ * </pre>
+ */
+public class SimpleRouter implements Router, Routes {
+    /** Routes. */
+    private final List<Route> routes;
+
+    /**
+     * Creates a new empty router.
+     */
+    public SimpleRouter() {
+        routes = new ArrayList<>();
+    }
+
+    /**
+     * Adds the route to router chain.
+     *
+     * @param route Route
+     */
+    @Override
+    public void addRoute(Route route) {
+        routes.add(route);
+    }
+
+    /**
+     * Finds the route by request.
+     *
+     * @param req Request.
+     * @return Route if founded.
+     */
+    @Override
+    public Optional<Route> route(HttpRequest req) {
+        return routes.stream().filter(r -> r.match(req)).findFirst();
+    }
+}
diff --git a/modules/rest/src/test/java/org/apache/ignite/internal/rest/routes/RouteTest.java b/modules/rest/src/test/java/org/apache/ignite/internal/rest/routes/RouteTest.java
index b747f87..8e0b8ea 100644
--- a/modules/rest/src/test/java/org/apache/ignite/internal/rest/routes/RouteTest.java
+++ b/modules/rest/src/test/java/org/apache/ignite/internal/rest/routes/RouteTest.java
@@ -28,6 +28,8 @@ import io.netty.handler.codec.http.DefaultHttpRequest;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpHeaderValues;
 import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.internal.rest.api.RequestHandler;
+import org.apache.ignite.internal.rest.api.Route;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index 12b177b..dd132e5 100644
--- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -40,6 +40,7 @@ import org.apache.ignite.internal.configuration.ConfigurationModule;
 import org.apache.ignite.internal.configuration.ConfigurationModules;
 import org.apache.ignite.internal.configuration.ConfigurationRegistry;
 import org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider;
+import org.apache.ignite.internal.configuration.rest.ConfigurationHttpHandlers;
 import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
 import org.apache.ignite.internal.configuration.storage.DistributedConfigurationStorage;
 import org.apache.ignite.internal.configuration.storage.LocalConfigurationStorage;
@@ -47,7 +48,7 @@ import org.apache.ignite.internal.manager.IgniteComponent;
 import org.apache.ignite.internal.metastorage.MetaStorageManager;
 import org.apache.ignite.internal.metastorage.server.persistence.RocksDbKeyValueStorage;
 import org.apache.ignite.internal.raft.Loza;
-import org.apache.ignite.internal.rest.RestModule;
+import org.apache.ignite.internal.rest.RestComponent;
 import org.apache.ignite.internal.sql.engine.QueryProcessor;
 import org.apache.ignite.internal.sql.engine.SqlQueryProcessor;
 import org.apache.ignite.internal.sql.engine.message.SqlQueryMessagesSerializationRegistryInitializer;
@@ -134,7 +135,7 @@ public class IgniteImpl implements Ignite {
     private final TableManager distributedTblMgr;
 
     /** Rest module. */
-    private final RestModule restModule;
+    private final RestComponent restComponent;
 
     /** Client handler module. */
     private final ClientHandlerModule clientHandlerModule;
@@ -181,6 +182,8 @@ public class IgniteImpl implements Ignite {
 
         nettyBootstrapFactory = new NettyBootstrapFactory(networkConfiguration, clusterLocalConfiguration.getName());
 
+        restComponent = new RestComponent(nodeCfgMgr, nettyBootstrapFactory);
+
         clusterSvc = new ScaleCubeClusterServiceFactory().createClusterService(
                 clusterLocalConfiguration,
                 networkConfiguration,
@@ -209,6 +212,8 @@ public class IgniteImpl implements Ignite {
                 modules.distributed().polymorphicSchemaExtensions()
         );
 
+        new ConfigurationHttpHandlers(nodeCfgMgr, clusterCfgMgr).registerHandlers(restComponent);
+
         baselineMgr = new BaselineManager(
                 clusterCfgMgr,
                 metaStorageMgr,
@@ -240,8 +245,6 @@ public class IgniteImpl implements Ignite {
                 distributedTblMgr
         );
 
-        restModule = new RestModule(nodeCfgMgr, clusterCfgMgr, nettyBootstrapFactory);
-
         clientHandlerModule = new ClientHandlerModule(
                 qryEngine,
                 distributedTblMgr,
@@ -333,7 +336,7 @@ public class IgniteImpl implements Ignite {
                     baselineMgr,
                     distributedTblMgr,
                     qryEngine,
-                    restModule,
+                    restComponent,
                     clientHandlerModule
             );
 
@@ -366,7 +369,7 @@ public class IgniteImpl implements Ignite {
     public void stop() {
         if (status.getAndSet(Status.STOPPING) == Status.STARTED) {
             doStopNode(List.of(vaultMgr, nodeCfgMgr, clusterSvc, raftMgr, txManager, metaStorageMgr, clusterCfgMgr, baselineMgr,
-                    distributedTblMgr, qryEngine, restModule, clientHandlerModule, nettyBootstrapFactory));
+                    distributedTblMgr, qryEngine, restComponent, clientHandlerModule, nettyBootstrapFactory));
         }
     }
 
diff --git a/modules/api/src/main/java/org/apache/ignite/configuration/CoreDistributedConfigurationModule.java b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModule.java
similarity index 96%
rename from modules/api/src/main/java/org/apache/ignite/configuration/CoreDistributedConfigurationModule.java
rename to modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModule.java
index e0639e0..fb97540 100644
--- a/modules/api/src/main/java/org/apache/ignite/configuration/CoreDistributedConfigurationModule.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModule.java
@@ -15,10 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.configuration;
+package org.apache.ignite.internal.configuration;
 
 import java.util.Collection;
 import java.util.List;
+import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.annotation.ConfigurationType;
 import org.apache.ignite.configuration.schemas.runner.ClusterConfiguration;
 import org.apache.ignite.configuration.schemas.store.DataStorageConfiguration;
@@ -29,7 +30,6 @@ import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchem
 import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema;
 import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema;
 import org.apache.ignite.configuration.schemas.table.TablesConfiguration;
-import org.apache.ignite.internal.configuration.ConfigurationModule;
 
 /**
  * {@link ConfigurationModule} for cluster-wide configuration provided by ignite-api.
diff --git a/modules/api/src/main/java/org/apache/ignite/configuration/CoreLocalConfigurationModule.java b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreLocalConfigurationModule.java
similarity index 94%
rename from modules/api/src/main/java/org/apache/ignite/configuration/CoreLocalConfigurationModule.java
rename to modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreLocalConfigurationModule.java
index 965bfca..63a8f7d 100644
--- a/modules/api/src/main/java/org/apache/ignite/configuration/CoreLocalConfigurationModule.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreLocalConfigurationModule.java
@@ -15,16 +15,16 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.configuration;
+package org.apache.ignite.internal.configuration;
 
 import java.util.Collection;
 import java.util.List;
+import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.annotation.ConfigurationType;
 import org.apache.ignite.configuration.schemas.clientconnector.ClientConnectorConfiguration;
 import org.apache.ignite.configuration.schemas.network.NetworkConfiguration;
 import org.apache.ignite.configuration.schemas.rest.RestConfiguration;
 import org.apache.ignite.configuration.schemas.runner.NodeConfiguration;
-import org.apache.ignite.internal.configuration.ConfigurationModule;
 
 /**
  * {@link ConfigurationModule} for node-local configuration provided by ignite-api.
diff --git a/modules/api/src/main/resources/META-INF/services/org.apache.ignite.internal.configuration.ConfigurationModule b/modules/runner/src/main/resources/META-INF/services/org.apache.ignite.internal.configuration.ConfigurationModule
similarity index 84%
rename from modules/api/src/main/resources/META-INF/services/org.apache.ignite.internal.configuration.ConfigurationModule
rename to modules/runner/src/main/resources/META-INF/services/org.apache.ignite.internal.configuration.ConfigurationModule
index e16f06d..cf110c9 100644
--- a/modules/api/src/main/resources/META-INF/services/org.apache.ignite.internal.configuration.ConfigurationModule
+++ b/modules/runner/src/main/resources/META-INF/services/org.apache.ignite.internal.configuration.ConfigurationModule
@@ -14,5 +14,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-org.apache.ignite.configuration.CoreLocalConfigurationModule
-org.apache.ignite.configuration.CoreDistributedConfigurationModule
+org.apache.ignite.internal.configuration.CoreLocalConfigurationModule
+org.apache.ignite.internal.configuration.CoreDistributedConfigurationModule
diff --git a/modules/api/src/test/java/org/apache/ignite/configuration/CoreDistributedConfigurationModuleTest.java b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModuleTest.java
similarity index 97%
rename from modules/api/src/test/java/org/apache/ignite/configuration/CoreDistributedConfigurationModuleTest.java
rename to modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModuleTest.java
index 84156b7..0672b12 100644
--- a/modules/api/src/test/java/org/apache/ignite/configuration/CoreDistributedConfigurationModuleTest.java
+++ b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModuleTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.configuration;
+package org.apache.ignite.internal.configuration;
 
 import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresent;
 import static org.apache.ignite.configuration.annotation.ConfigurationType.DISTRIBUTED;
@@ -34,7 +34,6 @@ import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchem
 import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema;
 import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema;
 import org.apache.ignite.configuration.schemas.table.TablesConfiguration;
-import org.apache.ignite.internal.configuration.ConfigurationModule;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/modules/api/src/test/java/org/apache/ignite/configuration/CoreLocalConfigurationModuleTest.java b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreLocalConfigurationModuleTest.java
similarity index 96%
rename from modules/api/src/test/java/org/apache/ignite/configuration/CoreLocalConfigurationModuleTest.java
rename to modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreLocalConfigurationModuleTest.java
index 46504ad..21f2796 100644
--- a/modules/api/src/test/java/org/apache/ignite/configuration/CoreLocalConfigurationModuleTest.java
+++ b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreLocalConfigurationModuleTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.configuration;
+package org.apache.ignite.internal.configuration;
 
 import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresent;
 import static org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
@@ -32,7 +32,6 @@ import org.apache.ignite.configuration.schemas.clientconnector.ClientConnectorCo
 import org.apache.ignite.configuration.schemas.network.NetworkConfiguration;
 import org.apache.ignite.configuration.schemas.rest.RestConfiguration;
 import org.apache.ignite.configuration.schemas.runner.NodeConfiguration;
-import org.apache.ignite.internal.configuration.ConfigurationModule;
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/parent/pom.xml b/parent/pom.xml
index 5e78340..42e5faf 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -239,6 +239,12 @@
 
             <dependency>
                 <groupId>org.apache.ignite</groupId>
+                <artifactId>ignite-rest-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.ignite</groupId>
                 <artifactId>ignite-rest</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/pom.xml b/pom.xml
index 81acea0..07b7974 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,6 +64,7 @@
         <module>modules/raft</module>
         <module>modules/raft-client</module>
         <module>modules/rest</module>
+        <module>modules/rest-api</module>
         <module>modules/rocksdb-common</module>
         <module>modules/runner</module>
         <module>modules/schema</module>