Skip to content

Service sdk cbor serde #1314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Jul 8, 2025
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,16 @@ class RpcV2Cbor : AwsHttpBindingProtocolGenerator() {
if (!op.hasHttpBody(ctx)) return

// payload member(s)
val requestBindings = resolver.requestBindings(op)
val httpPayload = requestBindings.firstOrNull { it.location == HttpBinding.Location.PAYLOAD }
val bindings = if (ctx.settings.build.generateServiceProject) {
resolver.responseBindings(op)
} else {
resolver.requestBindings(op)
}
val httpPayload = bindings.firstOrNull { it.location == HttpBinding.Location.PAYLOAD }
if (httpPayload != null) {
renderExplicitHttpPayloadSerializer(ctx, httpPayload, writer)
} else {
val documentMembers = requestBindings.filterDocumentBoundMembers()
val documentMembers = bindings.filterDocumentBoundMembers()
// Unbound document members that should be serialized into the document format for the protocol.
// delegate to the generate operation body serializer function
val sdg = structuredDataSerializer(ctx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,16 @@ open class StaticHttpBindingResolver(
/**
* By default returns all inputs as [HttpBinding.Location.DOCUMENT]
*/
override fun requestBindings(operationShape: OperationShape): List<HttpBindingDescriptor> {
if (!operationShape.input.isPresent) return emptyList()
val input = model.expectShape(operationShape.input.get())
return input.members().map { member -> HttpBindingDescriptor(member, HttpBinding.Location.DOCUMENT) }.toList()
override fun requestBindings(shape: Shape): List<HttpBindingDescriptor> {
when (shape) {
is OperationShape -> {
if (!shape.input.isPresent) return emptyList()
val input = model.expectShape(shape.input.get())
return input.members().map { member -> HttpBindingDescriptor(member, HttpBinding.Location.DOCUMENT) }.toList()
}
is StructureShape -> return shape.members().map { member -> member.toHttpBindingDescriptor() }.toList()
else -> error("unimplemented shape type for http response bindings: $shape")
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,17 @@ class CodegenVisitor(context: PluginContext) : ShapeVisitor.Default<Unit>() {
logger.info("[${service.id}] Generating service client for protocol $protocol")
generateProtocolClient(ctx)

logger.info("[${service.id}] Generating endpoint provider for protocol $protocol")
generateEndpointsSources(ctx)
if (!generateServiceProject) {
logger.info("[${service.id}] Generating endpoint provider for protocol $protocol")
generateEndpointsSources(ctx)

logger.info("[${service.id}] Generating auth scheme provider for protocol $protocol")
generateAuthSchemeProvider(ctx)
logger.info("[${service.id}] Generating auth scheme provider for protocol $protocol")
generateAuthSchemeProvider(ctx)
}
}

if (generateServiceProject) {
val serviceStubGenerator = ServiceStubGenerator(settings, writers)
val serviceStubGenerator = ServiceStubGenerator(baseGenerationContext, writers)
serviceStubGenerator.render()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ data class KotlinSettings(
* @return Returns the extracted settings
*/
fun from(model: Model, config: ObjectNode): KotlinSettings {
config.warnIfAdditionalProperties(listOf(SERVICE, PACKAGE_SETTINGS, BUILD_SETTINGS, SDK_ID, API_SETTINGS))
config.warnIfAdditionalProperties(listOf(SERVICE, PACKAGE_SETTINGS, BUILD_SETTINGS, SDK_ID, API_SETTINGS, SERVICE_STUB_SETTINGS))

val serviceId = config.getStringMember(SERVICE)
.map(StringNode::expectShapeId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ data class KotlinDependency(
// FIXME: version numbers should not be hardcoded, they should be setting dynamically based on the Gradle library versions
val KTOR_SERVER_CORE = KotlinDependency(GradleConfiguration.Implementation, "io.ktor.server", "io.ktor", "ktor-server-core", KTOR_VERSION)
val KTOR_SERVER_NETTY = KotlinDependency(GradleConfiguration.Implementation, "io.ktor.server.netty", "io.ktor", "ktor-server-netty", KTOR_VERSION)
val KTOR_SERVER_HTTP = KotlinDependency(GradleConfiguration.Implementation, "io.ktor.http", "io.ktor", "ktor-http-jvm", KTOR_VERSION)
val KTOR_LOGGING_BACKEND = KotlinDependency(GradleConfiguration.Implementation, "ch.qos.logback", "ch.qos.logback", "logback-classic", KTOR_LOGGING_BACKEND_VERSION)
val KTOR_SERVER_CONTENT_NEGOTIATION = KotlinDependency(GradleConfiguration.Implementation, "io.ktor.server.plugins.contentnegotiation", "io.ktor", "ktor-server-content-negotiation", KTOR_VERSION)
val KTOR_SERVER_CBOR_SERDE = KotlinDependency(GradleConfiguration.Implementation, "io.ktor.serialization.kotlinx.cbor", "io.ktor", "ktor-serialization-kotlinx-cbor", KTOR_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package software.amazon.smithy.kotlin.codegen.core

import software.amazon.smithy.codegen.core.*
import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes
import software.amazon.smithy.kotlin.codegen.lang.kotlinReservedWords
import software.amazon.smithy.kotlin.codegen.model.*
import software.amazon.smithy.kotlin.codegen.utils.dq
Expand Down Expand Up @@ -332,6 +333,10 @@ class KotlinSymbolProvider(private val model: Model, private val settings: Kotli
}

override fun serviceShape(shape: ServiceShape): Symbol {
if (settings.build.generateServiceProject) {
// Intentionally not generating a *client symbol* for the service
return KotlinTypes.Nothing
}
val serviceName = clientName(settings.sdkId)
return createSymbolBuilder(shape, "${serviceName}Client")
.namespace(rootNamespace, ".")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,6 @@ object RuntimeTypes {
}

object KtorServerCore : RuntimeTypePackage(KotlinDependency.KTOR_SERVER_CORE) {
val responseText = symbol("respondText", "response")
val embeddedServer = symbol("embeddedServer", "engine")
val Application = symbol("Application", "application")
val applicationCall = symbol("call", "application")
Expand All @@ -496,12 +495,23 @@ object RuntimeTypes {
object KtorServerRouting : RuntimeTypePackage(KotlinDependency.KTOR_SERVER_CORE) {
val routing = symbol("routing", "routing")
val get = symbol("get", "routing")
val post = symbol("post", "routing")

val responseText = symbol("respondText", "response")
val requestReceive = symbol("receive", "request")
val requestRespondBytes = symbol("respondBytes", "response")
}

object KtorServerNetty : RuntimeTypePackage(KotlinDependency.KTOR_SERVER_NETTY) {
val Netty = symbol("Netty")
}

object KtorServerHttp : RuntimeTypePackage(KotlinDependency.KTOR_SERVER_HTTP) {
val ContentType = symbol("ContentType")
val HttpStatusCode = symbol("HttpStatusCode")
val Cbor = symbol("Cbor", "ContentType.Application")
}

object KtorServerContentNegotiation : RuntimeTypePackage(KotlinDependency.KTOR_SERVER_CONTENT_NEGOTIATION) {
val ContentNegotiation = symbol("ContentNegotiation")
}
Expand Down
Loading
Loading