Xitrum Framework Documentation

repository·master·Indexed 19 days ago

https://github.com/xitrum-framework/xitrum

Xitrum is an asynchronous and clustered Scala web framework built on Netty, Akka, and Hazelcast. It features a high-performance built-in HTTP(S) server, support for clustering, and integrated tools for URL generation, internationalization (I18n) via .po files, request-scoped data management through HandlerEnv, and a built-in metrics viewer with SockJS streaming capabilities.

Tokens
9K
Snippets
30
Records
45
Agent score
66%

What's inside Xitrum

  1. Overview of the Xitrum framework

    master
    Xitrum is an asynchronous and clustered Scala web framework. It is built on top of Netty, Akka, and Hazelcast, and includes a high-performance built-in HTTP(S) server. The architecture allows for clustering where multiple instances of a web framework can communicate with each other via Akka and Hazelcast, while the underlying Netty layer handles client connections.
  2. Generate a dependency graph

    master

    You can visualize the project's dependency structure using Graphviz.

    1. Generate the .dot file using SBT:
    sbt dependencyDot
    1. Convert the generated target/dependencies-compile.dot file into a PNG image:
    dot -Tpng dependencies-compile.dot > deps.png
    sbt dependencyDot
  3. Publish Xitrum to your local machine

    master

    When developing, you can publish the current project to your local Ivy/SBT cache.

    To publish for the specific scalaVersion defined in build.sbt:

    sbt publishLocal

    To publish for all crossScalaVersions defined in the project:

    sbt "+ publishLocal"

    To clear all locally published Xitrum artifacts from your cache, use:

    find ~/.ivy2 -name *xitrum* -exec rm -rf {} \;
    sbt publishLocal
  4. Publish Xitrum to Sonatype

    master

    To release a new version to Sonatype, follow these steps:

    1. Prepare Credentials

    Create a ~/.sbt/1.0/sonatype.sbt file with your credentials:

    credentials += Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", "<your username>", "<your password>")

    2. Prepare the Build

    1. Temporarily remove -SNAPSHOT from the version in build.sbt.
    2. Uncomment publishArtifact in (Compile, packageDoc) := false in build.sbt (ensure it is NOT commented out).
    3. Append the contents of dev/build.sbt.end to the end of your build.sbt.
    4. Append the contents of dev/plugins.sbt.end to the end of project/plugins.sbt.

    3. Execute Publication

    Run the following command to publish and sign the artifacts:

    sbt "+ publishSigned"

    Note: If you encounter a GPG error on macOS, install GnuPG via Homebrew: brew install gnupg.

    4. Finalize on Sonatype

    Log in to oss.sonatype.org, locate your item in "Staging Repositories", and click "Close" then "Release".

    sbt "+ publishSigned"
  5. Use OptVar for optional variable access in an Action context

    master

    OptVar[+A] is an abstract class used to manage optional variables within an Action context. It provides a way to get, set, and remove values associated with a unique key (derived from the class name).

    Key Behaviors:

    • Type Safety & Recovery: If a value stored in the session does not match the expected type A (a ClassCastException scenario), OptVar will log a warning, clear the existing value to prevent the user from being stuck in a broken state, and then throw the exception. This is designed to allow users to recover (e.g., by clearing cookies) rather than being permanently stuck with an incompatible session variable.
    • Action Requirement: Almost all methods require an implicit Action parameter to manage the underlying data storage and logging.
  6. How ViewRenderer handles layouts and renderedView

    master

    The ViewRenderer uses a stateful approach to compose views and layouts. When you call renderView, the following lifecycle occurs:

    1. The template specified by the URI is rendered.
    2. The resulting string is assigned to the renderedView variable.
    3. The layout method is called. The layout method typically accesses renderedView to wrap the content in a common HTML structure (like a base template).

    If you need to bypass the layout, use renderViewNoLayout. If you need to provide a specific layout for a single request, use renderView with a custom layout function: renderView(() => myLayout, uri).

  7. Use HandlerEnv to access request-scoped data

    master

    The HandlerEnv class serves as a container for sharing data between handlers during a single request lifecycle. It acts as a type-safe map that provides direct access to common request components like the Netty Channel, the HTTP request and response objects, and parsed URL parameters.

    Key properties available in HandlerEnv include:

    • Routing & URL Data:

      • pathInfo: The URL path before the query string (e.g., /search).
      • queryParams: Parameters extracted from the query string.
      • pathParams: Parameters embedded in the route path (e.g., :id).
      • urlParams: A merged view of queryParams and pathParams (path parameters overwrite query parameters if keys collide).
      • route: The Route object that matched the request.
    • Body & Content Data:

      • bodyTextParams: Text-based parameters from the request body.
      • bodyFileParams: Sanitized file upload parameters.
      • textParams: A merged view of queryParams, bodyTextParams, and pathParams (path parameters overwrite others if keys collide).
      • requestContentString: The raw request body as a String, using the charset defined in Config.xitrum.request.charset.
      • requestContentJValue: The request body parsed as a JSON4S JValue. Returns an empty JObject() if the body is empty or invalid.

    Important: When using textParams, note that it is a lazy val. If you modify the underlying queryParams, bodyTextParams, or pathParams after textParams has already been accessed, the changes will not be reflected in the textParams object.

  8. Implement SockJS protocol handlers

    master

    To implement SockJS support in Xitrum, you should extend the provided traits and classes which handle the various SockJS transport mechanisms (WebSocket, XHR Polling, XHR Streaming, JSONP, EventSource, and HTML5 iframe).

    Key components for developers:

    • SockJsAction: The base trait for SockJS actions. It provides utilities for handling cookies (handleCookie()) and retrieving the required callback parameter (callbackParam()).
    • NonWebSocketSessionReceiverActorAction: Use this trait when implementing handlers for non-WebSocket transports (like XHR or JSONP) that require managing a session via an Akka Actor.
    • WebSocket: A specialized @WEBSOCKET action that integrates with the SockJS protocol, handling heartbeats and message normalization.

    Note: SockJS requires specific URL patterns involving serverId and sessionId. The ServerIdSessionIdValidator trait ensures these parameters do not contain dots, as per protocol requirements.

  9. Access the default Xitrum Metrics Viewer

    master

    Xitrum provides a built-in web interface for visualizing metrics. By default, it is available at the following endpoint:

    GET xitrum/metrics/viewer

    Security

    Access to this endpoint requires a valid api_key passed as a query parameter: ?api_key=<YOUR_API_KEY>

    Features

    • NodeMetrics Status: Visualizes Heap Memory (Committed, Used, Max) and CPU (Processors, Load Average) using tables and D3.js graphs.
    • Application Metrics: Displays Histograms (Count, Min, Max, Mean) from the application registry.
    • Focus Mode: If the focusAction parameter is provided in the query string, the viewer renders a simplified focusHtml layout designed for a specific metric key.
  10. Configure SockJS heartbeat and chunking limits

    master

    The SockJS implementation uses the following constants to manage connection stability and resource usage:

    • TIMEOUT_HEARTBEAT: Set to 25.seconds. The server must send a heartbeat frame (h) at this interval to keep the connection alive.
    • CHUNKED_RESPONSE_LIMIT: To prevent memory issues and force client garbage collection/reconnection, chunked transports are closed after a certain amount of data is sent.
      • In production mode: 128 * 1024 bytes.
      • In development mode: 4 * 1024 bytes.

    These values are controlled by the global Config.productionMode setting.

  11. Use SockJsAction for SockJS-compatible controllers

    master

    When creating controllers that participate in the SockJS ecosystem, extend SockJsAction. This provides access to protocol-specific requirements like cookie handling and path prefix management.

    Example of a basic SockJS greeting implementation:

    @GET("")
    class Greeting extends SockJsAction {
      def nLastTokensToRemoveFromPathInfo = 0
    
      def execute(): Unit = {
        respondText("Welcome to SockJS!\n")
      }
    }