Skip to content

Commit 4b998c6

Browse files
authored
feat: Enable general client generation from smithy models (#275)
1 parent 7a8d96a commit 4b998c6

File tree

9 files changed

+295
-60
lines changed

9 files changed

+295
-60
lines changed

build.gradle.kts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ plugins {
88
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
99
}
1010

11-
group = "aws.sdk.kotlin"
12-
1311
dependencies {
1412
dokkaPlugin(project(":dokka-aws"))
1513
}
@@ -82,9 +80,16 @@ tasks.dokkaHtmlMultiModule {
8280
removeChildTasks(excludeFromDocumentation)
8381
}
8482

85-
if (project.hasProperty("sonatypeUsername") && project.hasProperty("sonatypePassword")) {
83+
if (
84+
project.hasProperty("sonatypeUsername") &&
85+
project.hasProperty("sonatypePassword") &&
86+
project.hasProperty("publishGroupName")
87+
) {
8688
apply(plugin = "io.github.gradle-nexus.publish-plugin")
8789

90+
val publishGroupName = project.property("publishGroupName") as String
91+
group = publishGroupName
92+
8893
nexusPublishing {
8994
repositories {
9095
create("awsNexus") {

codegen/smithy-aws-kotlin-codegen/build.gradle.kts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
plugins {
66
kotlin("jvm")
77
jacoco
8+
`maven-publish`
89
}
910

1011
val sdkVersion: String by project
@@ -93,3 +94,26 @@ tasks.jacocoTestReport {
9394

9495
// Always run the jacoco test report after testing.
9596
tasks["test"].finalizedBy(tasks["jacocoTestReport"])
97+
98+
val sourcesJar by tasks.creating(Jar::class) {
99+
group = "publishing"
100+
description = "Assembles Kotlin sources jar"
101+
classifier = "sources"
102+
from(sourceSets.getByName("main").allSource)
103+
}
104+
105+
if (
106+
!project.hasProperty("publishGroupName") ||
107+
group.toString().startsWith(project.property("publishGroupName") as String)
108+
) {
109+
publishing {
110+
publications {
111+
create<MavenPublication>("codegen") {
112+
from(components["java"])
113+
artifact(sourcesJar)
114+
}
115+
}
116+
}
117+
118+
apply(from = rootProject.file("gradle/publish.gradle"))
119+
}

docs/howto/client-generator.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Generating a Kotlin Client from a Smithy Model
2+
3+
## Overview
4+
5+
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.
6+
7+
### Limitations
8+
9+
* The generated project requires some additions to the Gradle build file in order to successfully build the project (covered below).
10+
* 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.
11+
* You'll need to include all model dependencies directly in a local project.
12+
13+
### Prerequisites
14+
15+
* Intellij IDE installed locally
16+
* Kotlin AWS SDK installed locally (local maven repo)
17+
* A valid Smithy model
18+
19+
## Steps
20+
21+
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`.
22+
23+
1. Create a new Intellij Kotlin project, accepting defaults.
24+
2. Add the following lines to the already generated Gradle `build.gradle.kts` file:
25+
```kotlin
26+
plugins {
27+
...
28+
id("software.amazon.smithy").version("0.5.3")
29+
}
30+
```
31+
```kotlin
32+
dependencies {
33+
...
34+
// NOTE: More smithy dependencies may be required depending on what's referenced by your API models.
35+
implementation("software.amazon.smithy.kotlin:smithy-aws-kotlin-codegen:<latest version>")
36+
}
37+
```
38+
3. Add your model file(s) into a new directory at the root of your project called `model`.
39+
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:
40+
```json
41+
{
42+
"version": "1.0",
43+
"plugins": {
44+
"kotlin-codegen": {
45+
"service": "<namespace>#<service-name>",
46+
"package": {
47+
"name": "<namespace>",
48+
"version": "<version>",
49+
"description": "<service-name>"
50+
},
51+
"sdkId": "<service-name>",
52+
"build": {
53+
"generateDefaultBuildFiles": true,
54+
"optInAnnotations": [
55+
"aws.smithy.kotlin.runtime.util.InternalApi",
56+
"aws.sdk.kotlin.runtime.InternalSdkApi"
57+
],
58+
"rootProject": true
59+
}
60+
}}
61+
}
62+
```
63+
4. Run the `build` Gradle task to generate the service client.
64+
5. Look in `build/smithyprojections/<project name>/source/kotlin-codegen` for a generated Gradle project of the Kotlin client.

examples/build.gradle.kts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
plugins {
2-
kotlin("jvm") version "1.5.0"
2+
kotlin("jvm") version "1.5.20"
33
}
44

55
allprojects {
66
group = "aws.sdk.kotlin.example"
7-
version = "0.3.0-SNAPSHOT"
7+
version = "0.4.0-SNAPSHOT"
88

99
repositories {
10-
maven {
11-
name = "kotlinSdkLocal"
12-
url = uri(TODO("set your local repository path"))
13-
// e.g.
14-
//url = uri("file:///tmp/aws-sdk-kotlin-repo/m2")
15-
}
10+
mavenLocal()
1611
mavenCentral()
1712
}
1813
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
plugins {
2+
kotlin("jvm")
3+
id("software.amazon.smithy").version("0.5.3")
4+
}
5+
6+
val awsSdkKotlinVersion: String by project
7+
8+
dependencies {
9+
implementation("software.amazon.smithy.kotlin:smithy-aws-kotlin-codegen:$awsSdkKotlinVersion")
10+
// NOTE: More smithy dependencies may be required depending on what's referenced by your API models.
11+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
namespace example.weather
2+
3+
use aws.protocols#awsJson1_0
4+
use aws.api#service
5+
6+
@service(sdkId: "Weather")
7+
@awsJson1_0
8+
service Weather {
9+
version: "2006-03-01",
10+
resources: [City],
11+
operations: [GetCurrentTime]
12+
}
13+
14+
resource City {
15+
identifiers: { cityId: CityId },
16+
read: GetCity,
17+
list: ListCities,
18+
resources: [Forecast]
19+
}
20+
21+
resource Forecast {
22+
identifiers: { cityId: CityId },
23+
read: GetForecast
24+
}
25+
26+
// Pattern is a trait.
27+
@pattern("^[A-Za-z0-9 ]+$")
28+
string CityId
29+
30+
@readonly
31+
operation GetCurrentTime {
32+
output: GetCurrentTimeOutput
33+
}
34+
35+
structure GetCurrentTimeOutput {
36+
time: smithy.api#Timestamp
37+
}
38+
39+
@readonly
40+
operation GetForecast {
41+
input: GetForecastInput,
42+
output: GetForecastOutput,
43+
errors: [NoSuchResource]
44+
}
45+
46+
structure GetForecastInput {
47+
@required cityId: CityId
48+
}
49+
50+
structure GetForecastOutput {
51+
@required chanceOfRain: smithy.api#Float,
52+
@required low: smithy.api#Integer,
53+
@required high: smithy.api#Integer
54+
}
55+
56+
@readonly
57+
operation GetCity {
58+
input: GetCityInput,
59+
output: GetCityOutput,
60+
errors: [NoSuchResource]
61+
}
62+
63+
structure GetCityInput {
64+
@required cityId: CityId
65+
}
66+
67+
structure GetCityOutput {
68+
@required name: smithy.api#String,
69+
@required coordinates: CityCoordinates
70+
}
71+
72+
@readonly
73+
@paginated(inputToken: "nextToken", outputToken: "nextToken",
74+
pageSize: "pageSize", items: "items")
75+
operation ListCities {
76+
input: ListCitiesInput,
77+
output: ListCitiesOutput
78+
}
79+
80+
structure ListCitiesInput {
81+
nextToken: smithy.api#String,
82+
pageSize: smithy.api#Integer
83+
}
84+
85+
// Traits can be applied outside of the definition.
86+
apply ListCitiesInput @documentation("hello!")
87+
88+
structure ListCitiesOutput {
89+
nextToken: smithy.api#String,
90+
@required items: CitySummaries
91+
}
92+
93+
structure CityCoordinates {
94+
@required latitude: smithy.api#Float,
95+
@required longitude: smithy.api#Float
96+
}
97+
98+
@error("client")
99+
structure NoSuchResource {
100+
@required resourceType: smithy.api#String
101+
}
102+
103+
list CitySummaries {
104+
member: CitySummary
105+
}
106+
107+
@references([{resource: City}])
108+
structure CitySummary {
109+
@required cityId: CityId,
110+
@required name: smithy.api#String
111+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"version": "1.0",
3+
"plugins": {
4+
"kotlin-codegen": {
5+
"service": "example.weather#Weather",
6+
"package": {
7+
"name": "example.weather",
8+
"version": "0.1.0",
9+
"description": "Weather"
10+
},
11+
"sdkId": "Weather",
12+
"build": {
13+
"generateDefaultBuildFiles": true,
14+
"optInAnnotations": [
15+
"aws.smithy.kotlin.runtime.util.InternalApi",
16+
"aws.sdk.kotlin.runtime.InternalSdkApi"
17+
],
18+
"rootProject": true
19+
}
20+
}}
21+
}

examples/settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
rootProject.name = "aws-sdk-kotlin-examples"
22

3+
include(":client-generator")
34
include(":dynamodb-movies")
45
include(":s3-media-ingestion")

0 commit comments

Comments
 (0)