Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ exposed=0.+
h2=2.3.+
koin=3.5.+
kotlinx-rpc=0.9.1
kotlinx-rpc-grpc=0.10.0-grpc-121
kotlinx-html=0.+
mongo=4.10.+
postgres=42.7.+
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class SampleServiceImpl : SampleService {
override suspend fun greeting(name: ClientGreeting): ServerGreeting {
return ServerGreeting { content = "Hello, ${name.name}!" }
}
}
70 changes: 70 additions & 0 deletions plugins/server/org.jetbrains/kotlinx-rpc-grpc/3.0/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Add gRPC services to your Ktor application!

# Usage

## DISCLAIMER
**This is a dev preview of the kotlinx-rpc gRPC plugin for Ktor. It is not yet ready for production use.
The artifacts provided are dev artifacts, and the API may and will change in the future.**

**Please use it to play with the plugin. We will appreciate any feedback on the
[Github](https://github.com/Kotlin/kotlinx-rpc/issues)
or in [Slack](https://kotlinlang.slack.com/archives/C072YJ3Q91V)**

## gRPC Server
You can add gRPC services to your Ktor application by using the `grpc` function provided by the plugin.
Here's an example:

Declare a service in a `.proto` file.
```protobuf
syntax = "proto3";

message ClientGreeting {
string name = 1;
}

message ServerGreeting {
string content = 2;
}

service SampleService {
rpc greeting(ClientGreeting) returns (ServerGreeting);
}
```

The `SampleService` interface will generated for you alongside with other types and helper declarations.

Define an implementation. Then register it on the server and all done:

```kotlin
class SampleServiceImpl : SampleService {
override suspend fun greeting(name: ClientGreeting): ServerGreeting {
return ServerGreeting { content = "Hello, ${name.name}!" }
}
}

fun Application.module() {
grpc {
registerService<SampleService> { SampleServiceImpl() }
}
}
```

## gRPC Client
You can use any gRPC client on the other end, but also you can use ours!

To do that - use the `GrpcClient` class:
```Kotlin
val client = GrpcClient("localhost", 8081) {
usePlaintext()
}

val response = client.withService<SampleService>().greeting(
ClientGreeting {
name = "Alex"
}
)

assertEquals("Hello, Alex!", response.content, "Wrong response message")

client.close()
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import io.ktor.server.application.Application
import kotlinx.rpc.grpc.ktor.server.grpc
import kotlinx.rpc.registerService

fun Application.install() {
grpc {
registerService<SampleService> { SampleServiceImpl() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: gRPC
description: Add gRPC services to your Ktor server with kotlinx.rpc
vcsLink: https://github.com/Kotlin/kotlinx-rpc
license: Apache 2.0
category: Frameworks
maven:
disabled: true
# TODO KRPC-131 waiting for fixes to enable amper support
amper:
disabled: true
gradle:
pluginRepositories:
- url: https://maven.pkg.jetbrains.space/public/p/krpc/grpc
repositories:
- url: https://maven.pkg.jetbrains.space/public/p/krpc/grpc
plugins:
- id: org.jetbrains.kotlinx.rpc.plugin
version: $kotlinx-rpc-grpc
installation:
inside_app: inside_app.kt
test_function: test.kt
gradle_build: |-
rpc {
grpc()
}
sources:
- SampleServiceImpl.kt

# I need src/main/proto structure
#
#mainSourceSet:
# - proto/service.proto

# Or Maybe?
#src:
# - main:
# - proto:
Comment on lines +26 to +37
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm updating it so you can just write:

sources:
  - SampleServiceImpl.kt
  - service.proto

And it'll move the proto file into its own source folder.

Copy link
Member Author

@Mr3zee Mr3zee Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bjhham is this solution much easier than to make custom source mapping?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, custom source mappings would need a bit of extra work to ensure they play nice with the gradle vs. amper source folder layout logic. The new project templating engine I'm working on will have support for all that though.

# - proto/service.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
syntax = "proto3";

package io.ktor;

message ClientGreeting {
string name = 1;
}

message ServerGreeting {
string content = 2;
}

service SampleService {
rpc greeting(ClientGreeting) returns (ServerGreeting);
}
21 changes: 21 additions & 0 deletions plugins/server/org.jetbrains/kotlinx-rpc-grpc/3.0/stub.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// DO NOT DELETE, not included in generation, but is used for code highlighting in registry

class ClientGreeting {
var name: String = ""

companion object {
operator fun invoke(body: ClientGreeting.() -> Unit): ClientGreeting = ClientGreeting().apply(body)
}
}

class ServerGreeting {
var content: String = ""

companion object {
operator fun invoke(body: ServerGreeting.() -> Unit): ServerGreeting = ServerGreeting().apply(body)
}
}

interface SampleService {
suspend fun greeting(name: ClientGreeting): ServerGreeting
}
36 changes: 36 additions & 0 deletions plugins/server/org.jetbrains/kotlinx-rpc-grpc/3.0/test.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import io.ktor.server.testing.testApplication
import kotlinx.rpc.grpc.GrpcClient
import kotlinx.rpc.grpc.ktor.server.grpc
import kotlinx.rpc.registerService
import kotlinx.rpc.withService
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.time.Duration.Companion.minutes

class ApplicationRpcTest {
@Test
fun testRpc() = testApplication {
application {
grpc(8081) {
registerService<SampleService> { SampleServiceImpl() }
}
}

startApplication()

val client = GrpcClient("localhost", 8081) {
usePlaintext()
}

val response = client.withService<SampleService>().greeting(
ClientGreeting {
name = "Alex"
}
)

assertEquals("Hello, Alex!", response.content, "Wrong response message")

client.shutdown()
client.awaitTermination(1.minutes)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"[3.0,)":
- org.jetbrains.kotlinx:kotlinx-rpc-grpc-ktor-server:$kotlinx-rpc-grpc
- io.grpc:grpc-netty:1.73.0
- io.grpc:grpc-kotlin-stub:1.4.1