Core Concepts RESTHeart Cloud
Core Concepts
This page explains RESTHeart’s architecture and the key concepts you need to understand.
Prerequisites: Read Introduction to RESTHeart first.
The RESTHeart Runtime
At its core, RESTHeart is a runtime process (restheart-core) that:
-
Loads Configuration - Reads settings from configuration files or environment variables
-
Registers Plugins - Discovers and initializes plugins from the
plugins/directory -
Routes Requests - Maps incoming HTTP requests to the correct service
-
Enforces Security - Applies authentication and authorization rules
-
Executes Interceptors - Runs interceptors at various stages of request processing
-
Manages Lifecycle - Handles startup, shutdown, and plugin initialization
When you start RESTHeart with java -jar restheart.jar, this runtime process begins and loads everything needed to handle HTTP requests.
Standard Plugins
RESTHeart ships with standard plugins in the plugins/ directory:
plugins/
├── lib/ # Plugin dependencies
├── restheart-graphql.jar # GraphQL API
├── restheart-metrics.jar # Metrics and monitoring
├── restheart-mongoclient-provider.jar # MongoDB connection
├── restheart-mongodb.jar # REST API for MongoDB
├── restheart-polyglot.jar # JavaScript/TypeScript support
└── restheart-security.jar # Authentication & Authorization
These plugins provide the ready-to-use MongoDB APIs you can use without writing code.
Key point: These are just plugins! RESTHeart treats them the same as custom plugins you develop.
The Four Plugin Types
RESTHeart has four types of plugins, each serving a specific purpose:
1. Services
Purpose: Handle HTTP requests at specific URIs.
Use cases: - REST APIs - GraphQL endpoints - Custom business logic endpoints - File uploads/downloads - WebSocket connections
Example: The MongoDB REST API is implemented as a Service that handles requests to /{db}/{collection}.
Learn more: Developing Services
2. Interceptors
Purpose: Monitor and modify requests/responses as they flow through RESTHeart.
Use cases: - Logging requests - Adding custom headers - Transforming responses - Validating request data - Enforcing business rules
Intercept points:
- REQUEST_BEFORE_AUTH - Before authentication
- REQUEST_AFTER_AUTH - After authentication, before the service
- RESPONSE - After the service, before sending to client
- RESPONSE_ASYNC - Asynchronously after sending response
Example: A logging interceptor that records every API call.
Learn more: Developing Interceptors
3. Providers
Purpose: Supply objects to other plugins via dependency injection.
Use cases: - Database connections - Configuration objects - External API clients - Shared utilities
Example: The mongoclient-provider makes the MongoDB client available to other plugins with @Inject("mclient").
Learn more: Providers and Dependency Injection
4. Initializers
Purpose: Execute initialization logic at startup.
Use cases: - Database schema setup - Loading reference data - Starting background tasks - Warming up caches
Init points:
- BEFORE_STARTUP - Before RESTHeart starts accepting requests
- AFTER_STARTUP - After RESTHeart is ready
Example: An initializer that creates default database indexes on startup.
Learn more: Initializers
Request Lifecycle
Understanding how RESTHeart processes requests is key to working with the framework.
The Flow
1. HTTP Request arrives
↓
2. REQUEST_BEFORE_AUTH Interceptors run
↓
3. Authentication (identify the user)
↓
4. Authorization (check permissions)
↓
5. REQUEST_AFTER_AUTH Interceptors run
↓
6. Service handles the request
↓
7. RESPONSE Interceptors run
↓
8. HTTP Response sent to client
↓
9. RESPONSE_ASYNC Interceptors run (optional)
Understanding the Lifecycle
1. Virtual Threads = Simple Code
Each request runs in its own virtual thread. This means: - Your code is thread-safe by default (no shared state between requests) - No need for async/await or callbacks - Write straightforward, synchronous code - Excellent scalability (millions of concurrent requests)
2. Interceptor Execution Order
When multiple interceptors exist at the same point: - They run in order of priority (lower number = runs first) - Priority 1 runs before priority 10 - Use priorities to control execution sequence
3. Service Routing
RESTHeart matches requests to services by:
- URI patterns in @RegisterPlugin(defaultURI = "/myservice")
- First matching service handles the request
- Use specific patterns to avoid conflicts
== Plugin Discovery
RESTHeart automatically discovers plugins at startup:
Java/Kotlin Plugins
-
RESTHeart scans JAR files in
plugins/directory -
Looks for classes annotated with
@RegisterPlugin -
Instantiates and registers the plugins
Troubleshooting: If your plugin doesn’t load, check:
- JAR file is in the plugins/ directory
- Class has @RegisterPlugin annotation
- No compilation errors in the plugin
- Check logs for "Registered plugin" messages on startup
JavaScript Plugins
-
RESTHeart scans directories in
plugins/forpackage.json -
Loads JavaScript files as plugins
-
Executes via the polyglot plugin
Troubleshooting: JavaScript plugins require:
- GraalVM-based RESTHeart image (not standard image)
- Valid package.json with plugin definition
- restheart-polyglot.jar in plugins/ directory
Configuration
Plugin Configuration
Each plugin can have configuration in restheart.yml:
ping:
enabled: true
secure: false
uri: /ping
msg: 'Hello from RESTHeart!'
Special options:
- enabled - Enable/disable the plugin
- uri - Override default URI (Services only)
- secure - Require authentication (Services only)
Plugins access their configuration with:
@Inject("conf")
Map<String, Object> conf;
RESTHeart Configuration
Main configuration file: restheart.yml
Key sections:
- http-listener - Port, host, TLS settings
- mclient - MongoDB connection string
- mongo - MongoDB service configuration
- Plugin-specific sections
Override methods:
Configuration Override Methods:
1. Configuration File
$ java -jar restheart.jar custom-config.yml
2. Environment Variable (RHO)
Override specific settings without editing files:
$ RHO='/http-listener/port->9090' java -jar restheart.jar
RHO Syntax:
RHO='/path/to/setting->value'
-
Path uses forward slashes:
/section/subsection/key -
Arrow
→separates path from value -
Multiple overrides:
/setting1→value1;/setting2→value2
Examples:
# Change port
$ RHO='/http-listener/port->9090'
# Multiple overrides
$ RHO='/http-listener/port->9090;/mclient/connection-string->"mongodb://localhost"'
# Boolean value
$ RHO='/logging/log-to-console->false'
3. Override File
$ java -jar restheart.jar -o overrides.yml
Learn more: Configuration Guide
Dependency Injection
What is Dependency Injection?
Instead of creating objects yourself, RESTHeart provides (injects) them into your plugin. This gives you access to RESTHeart’s built-in services and configuration.
How it works:
1. Add @Inject("name") to a field in your plugin
2. RESTHeart automatically provides the object when your plugin loads
3. Use the injected object in your plugin code
Why use it: - Access MongoDB client without managing connections - Read configuration without parsing files - Use RESTHeart services without manual setup
RESTHeart provides dependency injection through the @Inject annotation.
Built-in Providers
@Inject("conf")
Map<String, Object> conf; // Plugin's configuration
@Inject("rh-config")
Configuration rhConfig; // RESTHeart's global configuration
@Inject("mclient")
MongoClient mclient; // MongoDB client
@Inject("registry")
PluginsRegistry registry; // Access other plugins
@Inject("acl-registry")
ACLRegistry aclRegistry; // Programmatic ACL management
Custom Providers
You can create your own providers to supply custom objects:
@RegisterPlugin(name = "myProvider", description = "Custom provider")
public class MyProvider implements Provider<MyService> {
@Override
public MyService get(PluginRecord<?> caller) {
return new MyService();
}
}
Then inject it:
@Inject("myProvider")
MyService myService;
Security Architecture
RESTHeart’s security has three layers:
1. Authentication Mechanisms
Extract credentials from requests (Basic Auth, JWT, tokens, etc.)
2. Authenticators
Verify credentials and build the user account (check username/password, validate JWT, etc.)
3. Authorizers
Check if the authenticated user has permission to perform the request (ACLs, role-based, etc.)
Security plugins let you customize any of these layers.
Learn more: - Security Fundamentals - Security Overview - Developing Security Plugins
Virtual Threads
RESTHeart uses Java 21’s virtual threads for superior performance:
Benefits: - Lightweight - Millions of virtual threads vs thousands of platform threads - Simple code - No async/await complexity - Better performance - Efficient resource utilization - Scalability - Handle massive concurrency
For developers: Write synchronous code that looks simple but scales massively.
// This looks synchronous but doesn't block platform threads
var data = mongoClient.find("db", "collection");
response.setContent(data);
Polyglot Support
RESTHeart supports multiple languages for plugin development:
Java
The native language, best performance:
@RegisterPlugin(name = "myService")
public class MyService implements JsonService {
public void handle(JsonRequest req, JsonResponse res) {
res.setContent(object().put("message", "Hello"));
}
}
Kotlin
Concise JVM language with full interop:
@RegisterPlugin(name = "myService")
class MyService : JsonService {
override fun handle(req: JsonRequest, res: JsonResponse) {
res.setContent(Json.obj().put("message", "Hello"))
}
}
JavaScript/TypeScript
Familiar syntax for web developers:
export const options = { name: "myService" }
export function handle(request, response) {
response.setContent(JSON.stringify({ message: "Hello" }));
response.setContentTypeAsJson();
}
Important differences from Node.js: - Runs on virtual threads (not Node’s event loop) - No need for async/await for I/O operations - Synchronous-style code that doesn’t block - No Node.js stdlib - use Java libraries instead
When to use JavaScript plugins: - Rapid prototyping - Simple request/response transformations - Leveraging JavaScript string/JSON manipulation - Teams with JavaScript expertise
When to use Java instead: - Performance-critical code - Complex business logic - Access to Java ecosystem libraries Important: JavaScript plugins run on virtual threads too - no async/await needed!
Performance Characteristics
Startup Time: ~100ms (with standard plugins) Memory Footprint: ~50MB heap (configurable) Request Latency: Sub-millisecond for simple operations Throughput: Hundreds of thousands of requests per second GraalVM Native: ~40MB binary, instant startup (<10ms)
Learn more: Performance Guide
What’s Next?
Now that you understand RESTHeart’s architecture:
Continue Foundations
-
Security Fundamentals - How security works
-
Setup Guide - Detailed installation
Start Building
-
Use MongoDB APIs: REST API Tutorial
-
Develop Plugins: Plugin Development Tutorial
Explore Topics
-
Configuration - Configure RESTHeart
-
Framework Overview - Plugin development details