Skip to content
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
11 changes: 8 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ plugins {
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
}

group = "aws.sdk.kotlin"

dependencies {
dokkaPlugin(project(":dokka-aws"))
}
Expand Down Expand Up @@ -82,9 +80,16 @@ tasks.dokkaHtmlMultiModule {
removeChildTasks(excludeFromDocumentation)
}

if (project.hasProperty("sonatypeUsername") && project.hasProperty("sonatypePassword")) {
if (
project.hasProperty("sonatypeUsername") &&
project.hasProperty("sonatypePassword") &&
project.hasProperty("publishGroupName")
) {
apply(plugin = "io.github.gradle-nexus.publish-plugin")

val publishGroupName = project.property("publishGroupName") as String
group = publishGroupName

nexusPublishing {
repositories {
create("awsNexus") {
Expand Down
24 changes: 24 additions & 0 deletions codegen/smithy-aws-kotlin-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
plugins {
kotlin("jvm")
jacoco
`maven-publish`
}

val sdkVersion: String by project
Expand Down Expand Up @@ -93,3 +94,26 @@ tasks.jacocoTestReport {

// Always run the jacoco test report after testing.
tasks["test"].finalizedBy(tasks["jacocoTestReport"])

val sourcesJar by tasks.creating(Jar::class) {
group = "publishing"
description = "Assembles Kotlin sources jar"
classifier = "sources"
from(sourceSets.getByName("main").allSource)
}

if (
!project.hasProperty("publishGroupName") ||
group.toString().startsWith(project.property("publishGroupName") as String)
) {
publishing {
publications {
create<MavenPublication>("codegen") {
from(components["java"])
artifact(sourcesJar)
}
}
}

apply(from = rootProject.file("gradle/publish.gradle"))
}
64 changes: 64 additions & 0 deletions docs/howto/client-generator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Generating a Kotlin Client from a Smithy Model

## Overview

This page covers how to generate a Kotlin client from any valid Smithy model. This generated Kotlin client could then be used to interact with a service instance from a Kotlin program. The Kotlin codegen is under active development and there remains several details that must be implemented before this approach can be used to create a fully functional client. However, using the code generator can give insights into how API models translate into working Kotlin code that service customers may interact with in the future.

### Limitations

* The generated project requires some additions to the Gradle build file in order to successfully build the project (covered below).
* AWS-specific logic will be included in the generated client that should be disregarded. In a future release this will be fixed. For now please ignore AWS specific logic such as AWS regions.
* You'll need to include all model dependencies directly in a local project.

### Prerequisites

* Intellij IDE installed locally
* Kotlin AWS SDK installed locally (local maven repo)
* A valid Smithy model

## Steps

The following steps will create a project that will codegen a client when built. Either follow these steps or check out the example provided in `/examples/client-generator`.

1. Create a new Intellij Kotlin project, accepting defaults.
2. Add the following lines to the already generated Gradle `build.gradle.kts` file:
```kotlin
plugins {
...
id("software.amazon.smithy").version("0.5.3")
}
```
```kotlin
dependencies {
...
// NOTE: More smithy dependencies may be required depending on what's referenced by your API models.
implementation("software.amazon.smithy.kotlin:smithy-aws-kotlin-codegen:<latest version>")
}
```
3. Add your model file(s) into a new directory at the root of your project called `model`.
1. Add a `smithy-build.json` file into the root of your project. Substitute `<namespace>`, `<service-name>`, and `<version>` for literals from your model and service:
```json
{
"version": "1.0",
"plugins": {
"kotlin-codegen": {
"service": "<namespace>#<service-name>",
"package": {
"name": "<namespace>",
"version": "<version>",
"description": "<service-name>"
},
"sdkId": "<service-name>",
"build": {
"generateDefaultBuildFiles": true,
"optInAnnotations": [
"aws.smithy.kotlin.runtime.util.InternalApi",
"aws.sdk.kotlin.runtime.InternalSdkApi"
],
"rootProject": true
}
}}
}
```
4. Run the `build` Gradle task to generate the service client.
5. Look in `build/smithyprojections/<project name>/source/kotlin-codegen` for a generated Gradle project of the Kotlin client.
11 changes: 3 additions & 8 deletions examples/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
plugins {
kotlin("jvm") version "1.5.0"
kotlin("jvm") version "1.5.20"
}

allprojects {
group = "aws.sdk.kotlin.example"
version = "0.3.0-SNAPSHOT"
version = "0.4.0-SNAPSHOT"

repositories {
maven {
name = "kotlinSdkLocal"
url = uri(TODO("set your local repository path"))
// e.g.
//url = uri("file:///tmp/aws-sdk-kotlin-repo/m2")
}
Comment on lines -10 to -15
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: Do we want to leave mavenLocal() here for local building/testing using the example projects?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, my assumption was that once we were public we wouldn't need this. What in particular will need a local dependency?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

discussed offline and added mavenLocal

mavenLocal()
mavenCentral()
}
}
11 changes: 11 additions & 0 deletions examples/client-generator/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
kotlin("jvm")
id("software.amazon.smithy").version("0.5.3")
}

val awsSdkKotlinVersion: String by project

dependencies {
implementation("software.amazon.smithy.kotlin:smithy-aws-kotlin-codegen:$awsSdkKotlinVersion")
// NOTE: More smithy dependencies may be required depending on what's referenced by your API models.
}
111 changes: 111 additions & 0 deletions examples/client-generator/model/weather-service.smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
namespace example.weather

use aws.protocols#awsJson1_0
use aws.api#service

@service(sdkId: "Weather")
@awsJson1_0
service Weather {
version: "2006-03-01",
resources: [City],
operations: [GetCurrentTime]
}

resource City {
identifiers: { cityId: CityId },
read: GetCity,
list: ListCities,
resources: [Forecast]
}

resource Forecast {
identifiers: { cityId: CityId },
read: GetForecast
}

// Pattern is a trait.
@pattern("^[A-Za-z0-9 ]+$")
string CityId

@readonly
operation GetCurrentTime {
output: GetCurrentTimeOutput
}

structure GetCurrentTimeOutput {
time: smithy.api#Timestamp
}

@readonly
operation GetForecast {
input: GetForecastInput,
output: GetForecastOutput,
errors: [NoSuchResource]
}

structure GetForecastInput {
@required cityId: CityId
}

structure GetForecastOutput {
@required chanceOfRain: smithy.api#Float,
@required low: smithy.api#Integer,
@required high: smithy.api#Integer
}

@readonly
operation GetCity {
input: GetCityInput,
output: GetCityOutput,
errors: [NoSuchResource]
}

structure GetCityInput {
@required cityId: CityId
}

structure GetCityOutput {
@required name: smithy.api#String,
@required coordinates: CityCoordinates
}

@readonly
@paginated(inputToken: "nextToken", outputToken: "nextToken",
pageSize: "pageSize", items: "items")
operation ListCities {
input: ListCitiesInput,
output: ListCitiesOutput
}

structure ListCitiesInput {
nextToken: smithy.api#String,
pageSize: smithy.api#Integer
}

// Traits can be applied outside of the definition.
apply ListCitiesInput @documentation("hello!")

structure ListCitiesOutput {
nextToken: smithy.api#String,
@required items: CitySummaries
}

structure CityCoordinates {
@required latitude: smithy.api#Float,
@required longitude: smithy.api#Float
}

@error("client")
structure NoSuchResource {
@required resourceType: smithy.api#String
}

list CitySummaries {
member: CitySummary
}

@references([{resource: City}])
structure CitySummary {
@required cityId: CityId,
@required name: smithy.api#String
}
21 changes: 21 additions & 0 deletions examples/client-generator/smithy-build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"version": "1.0",
"plugins": {
"kotlin-codegen": {
"service": "example.weather#Weather",
"package": {
"name": "example.weather",
"version": "0.1.0",
"description": "Weather"
},
"sdkId": "Weather",
"build": {
"generateDefaultBuildFiles": true,
"optInAnnotations": [
"aws.smithy.kotlin.runtime.util.InternalApi",
"aws.sdk.kotlin.runtime.InternalSdkApi"
],
"rootProject": true
}
}}
}
1 change: 1 addition & 0 deletions examples/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
rootProject.name = "aws-sdk-kotlin-examples"

include(":client-generator")
include(":dynamodb-movies")
include(":s3-media-ingestion")
Loading