Server is essentially a "heart" of Knot.x. It's scalable (vertically and horizontally), plugable (easy to extend), fault-tolerant and highly efficient reactive server based on Vert.x.
Like any HTTP server, Knot.x HTTP Server allows you to define supported routes. Defining routes and security is done with Open API 3 standard.
Knot.x Server enables plugging in custom behaviour for each supported route.
Each defined path
is processed by the chain of Handlers
that reacts on the request and is able to shape the response.
Tree of content
You will find docs in the README.md
files inside each of following modules:
- Server API that defines contracts.
- Server core that contains basic
handlers and HTTP Server implementation. - Common contains reusable helper methods grouped into modules (e.g. Knot.x Server Common Placeholders).
Knot.x HTTP Server is a verticle that listens for HTTP requests. It is responsible for handling the whole HTTP traffic that goes to the Knot.x instance.
Once the HTTP request comes to the Server following actions are happening:
- Server checks if there is a routing path defined for the incoming request path
and method. If no path supports this request,
404 Not Found
is returned in the response. - Server checks whether a routing operation has been defined for the incoming request.
If no handlers are defined in the operations for this route,
501 Not Implemented
is returned in the response. - Handlers processing starts. In case of operation handler failure, failure handlers are triggered.
- Handling is continued until any Handler ends (completes) the response. If none does,
500 Internal Server Error
is returned.
To run Knot.x HTTP Server, simply add an entry in the modules
configuration:
modules = {
server = "io.knotx.server.KnotxServerVerticle"
}
Details of the Knot.x HTTP Server can be configured with KnotxServerOptions
in the configuration file:
config.server.options.config {
# options defined here
}
More details about the module configuration can be found in Knot.x Launcher.
HTTP options such as port, connection windows size, default version of ALPN (HTTP/2, HTTP/1) etc.
can be configured with Vert.x HttpServerOptions
.
E.g. following configuration specifies the port Server is listening at:
config.server.options.config {
serverOptions {
port = 8080
}
}
Knot.x HTTP Server port can also be specified by the system property knotx.port
that takes
precedence over the value in the configuration file.
java -Dknotx.port=9999 ...
Knot.x Server implements the backpressure mechanism. It drops / rejects requests after exceeding a
certain number of requests at a time.
If Knot.x Server can NOT process incoming requests fast enough (the requests buffer limit has been reached),
Server drops requests and responds with a configurable response code (by default 429, "Too Many Requests"
).
Dropping requests can be configured with DropRequestOptions
After the buffer slots are released, new requests will be accepted and finally processed.
That solution prevent
OutOfMemoryError
errors when there are too many requests (e.g. during the peak hours). Additionally response times should be more stable when system is under high stress.
Knot.x Routing is defined with Open API 3 standard.
routingSpecificationLocation
is the path to the YAML Open API specification.
It can be an absolute path, a local path or remote url (with HTTP
).
config.server.options.config {
routingSpecificationLocation = /openapi.yaml
}
Routing Operation
defines handlers and failure handlers involved in the processing of HTTP request for a specific
operation
defined in the Routing Specification (linking is done
by operationId
):
Open Api YAML config:
...
paths:
/example*:
get:
operationId: my-example-operation
...
Routing Operations entry in Knot.x conf
config.server.options.config.routingOperations = ${routingOperations} [
{
operationId = my-example-operation
handlers = [
# list of handlers that handles the request in chain
]
failureHandlers = [
# list of failure handlers
]
}
]
Routing Handler is nothing else than a basic Vert.x Handler that operate on the RoutingContext
.
You may find more information about it in the API docs.
Each handler
is configured with Routing Handler Options.
Knot.x server makes use of the OpenAPI3RouterFactory
in order to combine OpenAPI routes specification with configured handlers. According to OpenAPI3RouterFactory
docs, handlers are loaded in this order:
- Body handler (Customizable with this#setBodyHandler(BodyHandler)
- Custom global handlers configurable with this#addGlobalHandler(Handler)
- Global security handlers defined in upper spec level
- Operation specific security handlers
- Generated validation handler
- User handlers or "Not implemented" handler
Also, operations
in the server are mounted in the definition order inside yaml specification.
Security for each operation defined in the Open API specification
is implemented in a form of AuthHandlers
.
In order to add security for the operation, you need to implement AuthHandlerFactory
that provides AuthHandler
of a proper type.
Open Api YAML config:
...
paths:
/example*:
get:
operationId: my-example-operation
security:
- myExampleBasicAuth: []
...
components:
securitySchemes:
myExampleBasicAuth:
type: http
scheme: basic
Routing Operations entry in Knot.x conf
config.server.options.config.securityHandlers = [
{
schema = myExampleBasicAuth
factory = myBasicAuthHandlerFactory
config = {
# any config passed to the AuthHandler
}
}
]
Also, you need to implement and register AuthHandlerFactory
.
For the example above:
name
would bemyBasicAuthHandlerFactory
Global Handlers
defines handlers that will be applied before any routing operation
.
Please note that you should not add a body handler inside that list. If you want to modify the
body use routing operation
handlers.
config.server.options.config.globalHandlers = [
{
name = myGlobalHandler
config {
// some configuration passed via factory to the handler
}
}
]
Each handler
is specified with Routing Handler Options.
To log every request incoming to the Knot.x HTTP Server setup LoggerHandler
as a globalHandler
. Use loggerHandler
factory and Access Log Options
structure in order to configure it to your needs.
config.server.options.config.globalHandlers = [
{
name = loggerHandler
config {
immediate = true
format = DEFAULT
}
}
]
By default, access logs are logged to the knotx-access.log
in the logs directory. To find more about
default logger configuration, please see Knot.x Launcher logback settings.
Of course you may also use loggerHandler
factory to log access to only specific routes via
routing operation
.