Expose Backend

Your stack:

Goal

Turn a Kotlin class into a remotely callable backend service using Graftcode Gateway - no Spring, no REST routes, no OpenAPI specs needed.

What You'll See

  • Create a small Kotlin class with public methods.
  • Host it through Graftcode Gateway using Docker.
  • Explore the exposed methods in Graftcode Vision - your service is now accessible from any app as a strongly-typed client.

Prerequisites

  • Docker installed and running
  • JDK 21 and Maven only if you build outside Docker - the Maven base image below already provides both for docker build

Step 1. Create a project folder

Create a new folder and set up a Maven project:

mkdir kotlin-energy-service
cd kotlin-energy-service

Create a pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>energy-service</artifactId>
    <version>1.0.0</version>

    <properties>
        <kotlin.version>2.0.21</kotlin.version>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/kotlin</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>${kotlin.version}</version>
                <executions>
                    <execution>
                        <id>compile</id>
                        <goals><goal>compile</goal></goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Step 2. Write a Kotlin class with public methods

Create the directory structure and a file src/main/kotlin/energy/EnergyPriceCalculator.kt:

package energy

class EnergyPriceCalculator {
    companion object {
        @JvmStatic
        fun getPrice(): Int {
            return (100..104).random()
        }
    }
}

This is a plain Kotlin class - no annotations, no frameworks, no special interfaces. The @JvmStatic annotation ensures the method is exposed as a static method on the JVM, making it directly discoverable by Graftcode Gateway. Any public method you write here will automatically become available for remote consumption once hosted.

Step 3. Host it with Graftcode Gateway

Create a Dockerfile in the project root:

FROM maven:3.9-eclipse-temurin-21

WORKDIR /usr/app

COPY . /usr/app/

RUN mvn package -q

RUN apt-get update \
 && apt-get install -y wget \
 && wget -O /usr/app/gg.deb https://github.com/grft-dev/graftcode-gateway/releases/latest/download/gg_linux_amd64.deb \
 && dpkg -i /usr/app/gg.deb \
 && rm /usr/app/gg.deb \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

EXPOSE 80
EXPOSE 81

CMD ["gg","--modules", "/usr/app/target/energy-service-1.0.0.jar"]
 

The key line is the last one - gg (Graftcode Gateway) reads your compiled JAR, discovers all public methods in your Kotlin classes, and exposes them automatically. Port 80 handles service calls, port 81 serves Graftcode Vision.

Build and run the container:

docker build --no-cache --pull -t myenergyservice-kotlin:test .
docker run -d -p 80:80 -p 81:81 --name graftcode_demo_kotlin myenergyservice-kotlin:test

Your Kotlin service is now running and exposed through Graftcode Gateway.

Step 4. Explore the service in Graftcode Vision

Open http://localhost:81/GV in your browser.

You will see all public methods from your Kotlin class - their names, parameter types, and return types. Gateway logs may also list a synthetic energy.Companion type created for the Kotlin companion object; the generated npm client typically exposes only EnergyPriceCalculator. Graftcode Vision also provides:

  • A "Try it out" button to call methods live, directly from the browser.
  • A package manager command (npm, NuGet, PyPI, Maven, etc.) to install this service as a strongly-typed client in any other application.

When calling the service through MCP (http://localhost:81/mcp), run tools/list first. Kotlin companion object + @JvmStatic can expose hashed / duplicate tool names (for example getPrice_b5df91ae for the static method and another hash for the Companion instance). A plain getPrice name may return MCP error

-32602 Invalid fully qualified member name
. Prefer the hashed name from tools/list, or call via the Graft npm client below.

Everything above works without any account - perfect for learning and local development. When you're ready for real-world usage, create a free account at portal.graftcode.com, set up a project, and copy its Project Key.

Then pass the key when starting your gateway:

CMD ["gg", "--modules", "/usr/app/target/energy-service-1.0.0.jar", "--projectKey", "YOUR_PROJECT_KEY"]

A Project Key gives you:

  • Stable registry URL - consumers always find and update your Graft through a permanent address, so install commands don't change when you redeploy.
  • Portal visibility - see all your gateways and exposed services in one place at gateways.graftcode.com.
  • Access control - decide who can download your Grafts using package manager authentication and permissions.
  • MCP endpoint - Graftcode Gateway automatically exposes an MCP (Model Context Protocol) endpoint alongside your service, making your methods callable by AI agents and LLM-based tools out of the box.

Step 6. Call it from another app

Your service is now accessible from any application. From Graftcode Vision, select your target package type - for example npm - and copy the generated install command. That installs a Graft: a strongly-typed client that lets any app call your service methods directly.

The generated package name comes from Maven groupId / artifactId (for this sample typically @graft/maven-groupid_com-example_artifactid_energy-service@1.0.0) and does not indicate that the backend was written in Kotlin. Always prefer the exact command from Vision or Gateway logs.

import com.graft.maven.energypricecalculator.EnergyPriceCalculator

val price = EnergyPriceCalculator.getPrice()
println(price)

No REST clients, no request/response models, no endpoint URLs in your code. When you add or update a public method, consumers update their Graft with a single package manager command.