|
1 | | -# Smithy Kotlin Service Codegen (Ktor) |
| 1 | +# Smithy Kotlin Service Codegen (SKSC) |
2 | 2 |
|
3 | 3 | ## Overview |
4 | 4 |
|
5 | | -This project extends **Smithy Kotlin** to generate **service-side code** from Smithy models, targeting the **Ktor** framework for server implementation. |
6 | | -It produces **complete service stubs**, including routing, serialization/deserialization, authentication, and validation, so developers can focus entirely on implementing business logic. |
7 | | - |
8 | | -While Ktor is the default backend, the architecture is framework-agnostic, allowing future support for other server frameworks. |
9 | | - |
10 | | ---- |
11 | | - |
12 | | -## Feature Summary |
13 | | - |
14 | | -| **Features** | **Description** | |
15 | | -|---------------------------|-----------------| |
16 | | -| Service Framework | Abstracted service framework interface and base implementation with Ktor as the default backend | |
17 | | -| CBOR Protocol | Support for CBOR serialization / deserialization and CBOR protocol traits | |
18 | | -| Json Protocol | Support for Json serialization / deserialization and Json protocol traits | |
19 | | -| Routing | Per-operation routing generation with Ktor DSL; ties to handler and validation | |
20 | | -| Error Handler | Unified exception handling logic mapped to HTTP status codes and support for error trait | |
21 | | -| Authentication (bearer) | Bearer token authentication middleware with model-driven configuration | |
22 | | -| Logging | Structured logging setup | |
23 | | -| Constraints Checker | Validation logic generated from Smithy traits and invoked pre-handler | |
24 | | -| Unit Test | Covers serialization/deserialization, routing, validation, and integration tests | |
25 | | - |
26 | | ---- |
27 | | - |
28 | | -## Smithy Protocol Traits Support |
29 | | - |
30 | | -| **Traits** | **CBOR Protocol** | **Json Protocol** | |
31 | | -|--------------------------|-------------------|-------------------| |
32 | | -| http | Yes | Yes | |
33 | | -| httpError | Yes | Yes | |
34 | | -| httpHeader | Not supported | Yes | |
35 | | -| httpPrefixHeader | Not supported | Yes | |
36 | | -| httpLabel | Not supported | Yes | |
37 | | -| httpQuery | Not supported | Yes | |
38 | | -| httpQueryParams | Not supported | Yes | |
39 | | -| httpPayload | Not supported | Yes | |
40 | | -| jsonName | Not supported | Yes | |
41 | | -| timestampFormat | Not supported | Yes | |
42 | | -| httpChecksumRequired | Not supported | Not implemented yet | |
43 | | -| requestCompression | Not implemented yet | Not implemented yet | |
44 | | - |
45 | 5 | --- |
46 | 6 |
|
47 | | -## Constraint Traits Support |
| 7 | +This project generate **service-side code** from Smithy models, producing **complete service stubs**, including routing, serialization/deserialization, authentication, and validation, so developers can focus entirely on implementing business logic. |
48 | 8 |
|
49 | | -| **Traits** | **CBOR Protocol** | **Json Protocol** | |
50 | | -|-----------------|------------------------------|------------------------------| |
51 | | -| required | Yes | Yes | |
52 | | -| length | Yes | Yes | |
53 | | -| pattern | Yes | Yes | |
54 | | -| private | Yes (handled by Smithy) | Yes (handled by Smithy) | |
55 | | -| range | Yes | Yes | |
56 | | -| uniqueItems | Yes | Yes | |
57 | | -| idRef | Not implemented yet | Not implemented yet | |
| 9 | +While Ktor is the default backend, the architecture is framework-agnostic, allowing future support for other server frameworks. |
58 | 10 |
|
59 | | ---- |
60 | 11 |
|
61 | 12 | ## Getting Started |
62 | 13 |
|
63 | | -### Step 1: Build & Publish Codegen to Local Maven |
64 | | -First, in **this repository**, build and publish the code generator locally: |
65 | | -```bash |
66 | | -./gradlew :codegen:smithy-kotlin-codegen:build |
67 | | -./gradlew publishToMavenLocal |
68 | | -``` |
69 | | - |
70 | | -### Step 2: Create a New Kotlin Project |
71 | | -Now, create a **new Kotlin project** where you will use the Smithy Kotlin service code generator. |
72 | | - |
73 | | -From this point forward, **all steps apply to the new Kotlin project** you just created. |
74 | | - |
75 | | - |
76 | | -### Step 3: Configure `build.gradle.kts` in the New Project |
77 | | - |
78 | | -```kotlin |
79 | | -plugins { |
80 | | - alias(libs.plugins.kotlin.jvm) |
81 | | - id("software.amazon.smithy.gradle.smithy-jar") version "1.3.0" // check for latest version |
82 | | - application |
83 | | -} |
84 | | - |
85 | | -repositories { |
86 | | - mavenLocal() |
87 | | - mavenCentral() |
88 | | -} |
89 | | - |
90 | | -dependencies { |
91 | | - smithyBuild("software.amazon.smithy.kotlin:smithy-kotlin-codegen:<codegenVersion>") |
92 | | - implementation("software.amazon.smithy.kotlin:smithy-aws-kotlin-codegen:<codegenVersion>") |
93 | | - implementation("software.amazon.smithy:smithy-model:<smithyVersion>") |
94 | | - implementation("software.amazon.smithy:smithy-build:<smithyVersion>") |
95 | | - implementation("software.amazon.smithy:smithy-aws-traits:<smithyVersion>") |
96 | | - ... |
97 | | -} |
98 | | -``` |
99 | | - |
100 | | - |
101 | | -### Step 4: Create `smithy-build.json` in the New Project |
102 | | -This is an example of smithy-build.json. |
103 | | -```json |
104 | | -{ |
105 | | - "version": "1.0", |
106 | | - "outputDirectory": "build/generated-src", |
107 | | - "plugins": { |
108 | | - "kotlin-codegen": { |
109 | | - "service": "com.demo#DemoService", |
110 | | - "package": { |
111 | | - "name": "com.demo.server", |
112 | | - "version": "1.0.0" |
113 | | - }, |
114 | | - "build": { |
115 | | - "rootProject": true, |
116 | | - "generateServiceProject": true, |
117 | | - "optInAnnotations": [ |
118 | | - "aws.smithy.kotlin.runtime.InternalApi", |
119 | | - "kotlinx.serialization.ExperimentalSerializationApi" |
120 | | - ] |
121 | | - }, |
122 | | - "serviceStub": { |
123 | | - "framework": "ktor" |
124 | | - } |
125 | | - } |
126 | | - } |
127 | | -} |
128 | | -``` |
129 | | - |
130 | | -**Notes:** |
131 | | -- The most important fields are: |
132 | | - - **`outputDirectory`** — defines where the generated service code will be placed in your new project. |
133 | | - - **`service`** — must match your Smithy model’s `<namespace>#<service shape name>`. |
134 | | - - **`serviceStub.framework`** — defines the server framework for generated code. Currently only `"ktor"` is supported. |
135 | | - |
136 | | -### Step 5: Define Your Smithy Model in the New Project |
137 | | - |
138 | | -Create a `model` directory and add your `.smithy` files. |
139 | | -Example `model/greeter.smithy`: |
140 | | - |
141 | | -```smithy |
142 | | -$version: "2.0" |
143 | | -namespace com.demo |
144 | | -
|
145 | | -use aws.protocols#restJson1 |
146 | | -use smithy.api#httpBearerAuth |
147 | | -
|
148 | | -@restJson1 |
149 | | -@httpBearerAuth |
150 | | -service DemoService { |
151 | | - version: "1.0.0" |
152 | | - operations: [ |
153 | | - SayHello |
154 | | - ] |
155 | | -} |
156 | | -
|
157 | | -@http(method: "POST", uri: "/greet", code: 201) |
158 | | -operation SayHello { |
159 | | - input: SayHelloInput |
160 | | - output: SayHelloOutput |
161 | | - errors: [ |
162 | | - CustomError |
163 | | - ] |
164 | | -} |
165 | | -
|
166 | | -@input |
167 | | -structure SayHelloInput { |
168 | | - @required |
169 | | - @length(min: 3, max: 10) |
170 | | - name: String |
171 | | - @httpHeader("X-User-ID") |
172 | | - id: Integer |
173 | | -} |
| 14 | +--- |
174 | 15 |
|
175 | | -@output |
176 | | -structure SayHelloOutput { |
177 | | - greeting: String |
178 | | -} |
| 16 | +- Get an [introduction to Smithy](https://smithy.io/2.0/index.html) |
| 17 | +- Follow [Smithy's quickstart guide](https://smithy.io/2.0/quickstart.html) |
| 18 | +- See the [Guide](docs/GettingStarted.md) to learn how to use SKSC to generate service. |
| 19 | +- See a [Summary of Service Support](docs/Summary.md) to learn which features are supported |
179 | 20 |
|
180 | | -@error("server") |
181 | | -@httpError(500) |
182 | | -structure CustomError { |
183 | | - msg: String |
184 | | - @httpHeader("X-User-error") |
185 | | - err: String |
186 | | -} |
187 | | -``` |
188 | 21 |
|
189 | | -### Step 6: Generate the Service in the New Project |
| 22 | +## Development |
190 | 23 |
|
191 | | -Run: |
192 | | -```bash |
193 | | -gradle build run |
194 | | -``` |
195 | | - |
196 | | -If you want to clean previously generated code: |
197 | | -```bash |
198 | | -gradle clean |
199 | | -``` |
| 24 | +--- |
200 | 25 |
|
201 | | -### Step 7: Run the Generated Service |
| 26 | +### Module Structure |
202 | 27 |
|
203 | | -The generated service will be in the directory specified in `smithy-build.json` (`outputDirectory`). |
204 | | -You can start it by running: |
205 | | -```bash |
206 | | -gradle run |
207 | | -``` |
208 | | -By default, it listens on port **8080**. |
| 28 | +- `constraints` – directory that contains the constraints validation generator. |
| 29 | + - `ConstraintsGenerator.kt` - main generator for constraints. |
| 30 | + - `ConstraintUtilsGenerator` - generator for constraint utilities. |
| 31 | + - For each constraint trait, there is a dedicated file. |
| 32 | +- `ktor` – directory that stores all features generators specific to Ktor. |
| 33 | + - `ktorStubGenerator.kt` – main generator for ktor framework service stub generator. |
| 34 | +- `ServiceStubConfiguration.kt` – configuration file for the service stub generator. |
| 35 | +- `ServiceStubGenerator.kt` – abstract service stub generator file. |
| 36 | +- `ServiceTypes.kt` – file that includes service component symbols. |
| 37 | +- `utils.kt` – utilities file. |
209 | 38 |
|
210 | | -### Step 8: Adjust Service Configuration |
| 39 | +### Testing |
211 | 40 |
|
212 | | -You can override runtime settings (such as port or HTTP engine) using command-line arguments: |
| 41 | +The **service code generation tests** are located in `tests/codegen/service-codegen-tests`. These end-to-end tests generate the service, launch the server, send HTTP requests to validate functionality, and then shut down the service once testing is complete. This process typically takes around 2 minutes. To run tests specifically for SKSC, use the following command: |
213 | 42 | ```bash |
214 | | -gradle run --args="port 8000 engineFactory cio" |
215 | | -``` |
216 | | - |
217 | | ---- |
218 | | - |
219 | | -## Notes |
220 | | -- **Business Logic**: Implement your own logic in the generated operation handler interfaces. |
221 | | -- **Configuration**: Adjust port, engine, auth, and other settings via `ServiceFrameworkConfig` or CLI args. |
222 | | -- **Future Extensions**: Planned support for more serialization formats (JSON, XML) and AWS SigV4 auth. |
| 43 | + ./gradlew :tests:codegen:service-codegen-tests:test |
| 44 | +``` |
0 commit comments