diff --git a/settings.gradle.kts b/settings.gradle.kts index 220fb0e..eb582be 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -64,3 +64,7 @@ include(":smithy-java-examples:integ") // ---- Smithy-Rust examples ---- // templates includeBuild("smithy-rs-examples/quickstart-rust") + +// ---- Smithy-Kotlin examples ---- +// templates +includeBuild("smithy-kotlin-examples/quickstart-kotlin") diff --git a/smithy-kotlin-examples/README.MD b/smithy-kotlin-examples/README.MD new file mode 100644 index 0000000..eb2dcae --- /dev/null +++ b/smithy-kotlin-examples/README.MD @@ -0,0 +1,2 @@ +# Smithy Kotlin +The examples in this directory demonstrate the use of the [Smithy Kotlin](https://github.com/smithy-lang/smithy-kotlin) code generator for clients. \ No newline at end of file diff --git a/smithy-kotlin-examples/quickstart-kotlin/README.MD b/smithy-kotlin-examples/quickstart-kotlin/README.MD new file mode 100644 index 0000000..1dec5f4 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/README.MD @@ -0,0 +1,30 @@ +## Smithy-Kotlin Quickstart + +This project provides a template to get started using [Smithy Kotlin](https://github.com/smithy-lang/smithy-kotlin) +to create Kotlin clients. + +### Layout + +- `client/`: Code generated Kotlin client that can call the server. +- `smithy/`: Common package for the service API model. Shared by both client and server. +- `server/`: Code generated Java Server that implements stubbed operations code-generated from the service model. + +### Usage + +To create a new project from this template, use the [Smithy CLI](https://smithy.io/2.0/guides/smithy-cli/index.html) +`init` command as follows: + +```console +smithy init -t smithy-kotlin-quickstart +``` + +### Running and testing client + +To run and test the client, first start a server by running `./gradlew :server:run` from the root of a project created from this +template. That will start the server running on port `8888`. + +Once the server is running you can run the client application in the `client` subproject + +```console +./gradlew :client:run +``` diff --git a/smithy-kotlin-examples/quickstart-kotlin/build.gradle.kts b/smithy-kotlin-examples/quickstart-kotlin/build.gradle.kts new file mode 100644 index 0000000..fca222d --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/build.gradle.kts @@ -0,0 +1,8 @@ + +// Add repositories for all subprojects to resolve dependencies. +allprojects { + repositories { + mavenLocal() + mavenCentral() + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/client/build.gradle.kts b/smithy-kotlin-examples/quickstart-kotlin/client/build.gradle.kts new file mode 100644 index 0000000..f804e59 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/client/build.gradle.kts @@ -0,0 +1,49 @@ +description = "Coffee shop service client" + +plugins { + application + kotlin("jvm") version "2.3.0" + // Executes smithy-build process to generate client code + id("software.amazon.smithy.gradle.smithy-base") +} + +// Add generated client source code to the main sourceSet +afterEvaluate { + val clientPath = smithy.getPluginProjectionPath(smithy.sourceProjection.get(), "kotlin-codegen") + sourceSets.main.get().kotlin.srcDir(clientPath) +} + +tasks.named("compileKotlin") { + dependsOn("smithyBuild") +} + +dependencies { + // Code generators + compileOnly(libs.smithy.kotlin.aws.codegen) + + // Service model + implementation(project(":smithy")) + + // Client Dependencies + implementation(libs.smithy.kotlin.runtime.core) + implementation(libs.smithy.kotlin.smithy.client) + implementation(libs.smithy.kotlin.http.client) + implementation(libs.smithy.kotlin.telemetry.api) + implementation(libs.smithy.kotlin.telemetry.defaults) + implementation(libs.smithy.kotlin.rpcv2.protocol) + implementation(libs.smithy.kotlin.aws.protocol.core) + implementation(libs.smithy.kotlin.aws.signing.common) + implementation(libs.smithy.kotlin.serde) + implementation(libs.smithy.kotlin.serde.cbor) + implementation(libs.smithy.kotlin.http.client.engine.default) + implementation(libs.kotlinx.coroutines.core) +} + +val optinAnnotations = listOf("kotlin.RequiresOptIn", "aws.smithy.kotlin.runtime.InternalApi") +kotlin.sourceSets.all { + optinAnnotations.forEach { languageSettings.optIn(it) } +} + +application { + mainClass.set("io.smithy.kotlin.client.example.MainKt") +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/client/smithy-build.json b/smithy-kotlin-examples/quickstart-kotlin/client/smithy-build.json new file mode 100644 index 0000000..ff8f8e4 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/client/smithy-build.json @@ -0,0 +1,20 @@ +{ + "version": "1.0", + "plugins": { + "kotlin-codegen": { + "service": "com.example#CoffeeShop", + "sdkId": "CoffeeShop", + "package": { + "name": "io.smithy.kotlin.client.example", + "version": "0.0.1" + }, + "build": { + "rootProject": false, + "generateDefaultBuildFiles": false + }, + "api": { + "nullabilityCheckMode": "client" + } + } + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/client/src/main/kotlin/io/smithy/kotlin/client/example/Main.kt b/smithy-kotlin-examples/quickstart-kotlin/client/src/main/kotlin/io/smithy/kotlin/client/example/Main.kt new file mode 100644 index 0000000..6343866 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/client/src/main/kotlin/io/smithy/kotlin/client/example/Main.kt @@ -0,0 +1,37 @@ +package io.smithy.kotlin.client.example + +import aws.smithy.kotlin.runtime.client.endpoints.Endpoint +import io.smithy.kotlin.client.example.endpoints.CoffeeShopEndpointProvider +import io.smithy.kotlin.client.example.model.CoffeeType +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import java.util.logging.Logger +import kotlin.time.Duration.Companion.seconds + +fun main(): Unit = runBlocking { + val logger: Logger = Logger.getLogger("SmithyKotlinClient") + + CoffeeShopClient { + endpointProvider = CoffeeShopEndpointProvider { + Endpoint("http://localhost:8888") + } + }.use { client -> + logger.info("Creating coffee order") + + val createOrderResponse = client.createOrder { + coffeeType = CoffeeType.Latte + } + + logger.info("Created order with ID: ${createOrderResponse.id}") + + logger.info("Waiting for order to complete.") + delay(5.seconds) + + logger.info("Checking order status") + val orderStatus = client.getOrder { + id = createOrderResponse.id + }.status + + logger.info("Order status: $orderStatus") + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/gradle/libs.versions.toml b/smithy-kotlin-examples/quickstart-kotlin/gradle/libs.versions.toml new file mode 100644 index 0000000..e903caf --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/gradle/libs.versions.toml @@ -0,0 +1,29 @@ +[versions] +smithy-version="1.63.0" +smithy-java-version="0.0.1" +smithy-kotlin-codegen-version="0.35.25" +smithy-kotlin-runtime-version="1.5.25" +coroutines-core-version="1.10.2" + +[libraries] +smithy-aws-traits = { module="software.amazon.smithy:smithy-aws-traits", version.ref = "smithy-version" } + +smithy-java-plugins = { module="software.amazon.smithy.java.codegen:plugins", version.ref = "smithy-java-version" } +smithy-java-server-netty = { module="software.amazon.smithy.java:server-netty", version.ref = "smithy-java-version" } +smithy-java-aws-server-restjson = { module="software.amazon.smithy.java:aws-server-restjson", version.ref = "smithy-java-version" } +smithy-java-aws-server-rpcv2-cbor = { module="software.amazon.smithy.java:server-rpcv2-cbor", version.ref = "smithy-java-version" } + +smithy-kotlin-aws-codegen = { module = "software.amazon.smithy.kotlin:smithy-aws-kotlin-codegen", version.ref = "smithy-kotlin-codegen-version" } +smithy-kotlin-runtime-core = { module = "aws.smithy.kotlin:runtime-core", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-smithy-client = { module = "aws.smithy.kotlin:smithy-client", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-http-client = { module = "aws.smithy.kotlin:http-client", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-telemetry-api = { module = "aws.smithy.kotlin:telemetry-api", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-telemetry-defaults = { module = "aws.smithy.kotlin:telemetry-defaults", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-rpcv2-protocol = { module = "aws.smithy.kotlin:smithy-rpcv2-protocols", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-aws-protocol-core = { module = "aws.smithy.kotlin:aws-protocol-core", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-aws-signing-common = { module = "aws.smithy.kotlin:aws-signing-common", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-serde = { module = "aws.smithy.kotlin:serde", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-serde-cbor = { module = "aws.smithy.kotlin:serde-cbor", version.ref = "smithy-kotlin-runtime-version" } +smithy-kotlin-http-client-engine-default = { module = "aws.smithy.kotlin:http-client-engine-default", version.ref = "smithy-kotlin-runtime-version" } + +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines-core-version" } diff --git a/smithy-kotlin-examples/quickstart-kotlin/license.txt b/smithy-kotlin-examples/quickstart-kotlin/license.txt new file mode 100644 index 0000000..2dd564b --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/license.txt @@ -0,0 +1,4 @@ +/* + * Example file license header. + * File header line two + */ \ No newline at end of file diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/build.gradle.kts b/smithy-kotlin-examples/quickstart-kotlin/server/build.gradle.kts new file mode 100644 index 0000000..67a7453 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/build.gradle.kts @@ -0,0 +1,40 @@ +description = "Coffee shop service server implementation" + +plugins { + `java-library` + application + // Executes smithy-build process to generate server stubs + id("software.amazon.smithy.gradle.smithy-base") +} + +dependencies { + // Code generators + smithyBuild(libs.smithy.java.plugins) + + // Service model + implementation(project(":smithy")) + + // Server dependencies + // Adds an HTTP server implementation based on netty + implementation(libs.smithy.java.server.netty) + // Adds a server implementation of the `RestJson1` protocol + implementation(libs.smithy.java.aws.server.restjson) + // Adds a server implementation of the `Rpcv2Cbor` protocol + implementation(libs.smithy.java.aws.server.rpcv2.cbor) +} + +// Add generated source code to the compilation sourceSet +afterEvaluate { + val serverPath = smithy.getPluginProjectionPath(smithy.sourceProjection.get(), "java-server-codegen") + sourceSets.main.get().java.srcDir(serverPath) +} + +tasks.named("compileJava") { + dependsOn("smithyBuild") +} + +// Use the application plugin to start the service via the `run` task. +application { + mainClass = "io.smithy.kotlin.server.example.CoffeeShopService" +} + diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/smithy-build.json b/smithy-kotlin-examples/quickstart-kotlin/server/smithy-build.json new file mode 100644 index 0000000..57b0154 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/smithy-build.json @@ -0,0 +1,10 @@ +{ + "version": "1.0", + "plugins": { + "java-server-codegen": { + "service": "com.example#CoffeeShop", + "namespace": "io.smithy.kotlin.server.example", + "headerFile": "../license.txt" + } + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/CoffeeShopService.java b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/CoffeeShopService.java new file mode 100644 index 0000000..d5ef9b7 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/CoffeeShopService.java @@ -0,0 +1,46 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: MIT-0 + */ + +package io.smithy.kotlin.server.example; + +import io.smithy.kotlin.server.example.service.CoffeeShop; +import java.net.URI; +import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; +import software.amazon.smithy.java.server.Server; + +public class CoffeeShopService implements Runnable { + private static final Logger LOGGER = Logger.getLogger(CoffeeShopService.class.getName()); + + public static void main(String... args) throws InterruptedException, ExecutionException { + new CoffeeShopService().run(); + } + + @Override + public void run() { + Server server = Server.builder() + .endpoints(URI.create("http://localhost:8888")) + .addService( + CoffeeShop.builder() + .addCreateOrderOperation(new CreateOrder()) + .addGetMenuOperation(new GetMenu()) + .addGetOrderOperation(new GetOrder()) + .build() + ) + .build(); + LOGGER.info("Starting server..."); + server.start(); + try { + Thread.currentThread().join(); + } catch (InterruptedException e) { + LOGGER.info("Stopping server..."); + try { + server.shutdown().get(); + } catch (InterruptedException | ExecutionException ex) { + throw new RuntimeException(ex); + } + } + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/CreateOrder.java b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/CreateOrder.java new file mode 100644 index 0000000..757d977 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/CreateOrder.java @@ -0,0 +1,36 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: MIT-0 + */ + +package io.smithy.kotlin.server.example; + +import io.smithy.kotlin.server.example.model.CreateOrderInput; +import io.smithy.kotlin.server.example.model.CreateOrderOutput; +import io.smithy.kotlin.server.example.model.OrderStatus; +import io.smithy.kotlin.server.example.service.CreateOrderOperation; +import java.util.UUID; + +import java.util.logging.Logger; +import software.amazon.smithy.java.server.RequestContext; + +/** + * Create an order for a coffee. + */ +final class CreateOrder implements CreateOrderOperation { + private static final Logger LOGGER = Logger.getLogger(CreateOrder.class.getName()); + + @Override + public CreateOrderOutput createOrder(CreateOrderInput input, RequestContext context) { + var id = UUID.randomUUID(); + OrderTracker.putOrder(new Order(id, input.coffeeType(), OrderStatus.IN_PROGRESS)); + + LOGGER.info("Created order " + id + " for a " + input.coffeeType()); + + return CreateOrderOutput.builder() + .id(id.toString()) + .coffeeType(input.coffeeType()) + .status(OrderStatus.IN_PROGRESS) + .build(); + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/GetMenu.java b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/GetMenu.java new file mode 100644 index 0000000..571807c --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/GetMenu.java @@ -0,0 +1,59 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: MIT-0 + */ + +package io.smithy.kotlin.server.example; + +import io.smithy.kotlin.server.example.model.CoffeeItem; +import io.smithy.kotlin.server.example.model.CoffeeType; +import io.smithy.kotlin.server.example.model.GetMenuInput; +import io.smithy.kotlin.server.example.model.GetMenuOutput; +import io.smithy.kotlin.server.example.service.GetMenuOperation; +import java.util.List; + +import software.amazon.smithy.java.server.RequestContext; + +/** + * Returns the menu for the coffee shop + */ +final class GetMenu implements GetMenuOperation { + private static final List MENU = List.of( + CoffeeItem.builder() + .typeMember(CoffeeType.DRIP) + .description(""" + A clean-bodied, rounder, and more simplistic flavour profile. + Often praised for mellow and less intense notes. + Far less concentrated than espresso. + """) + .build(), + CoffeeItem.builder() + .typeMember(CoffeeType.POUR_OVER) + .description(""" + Similar to drip coffee, but with a process that brings out more subtle nuances in flavor. + More concentrated than drip, but less than espresso. + """) + .build(), + CoffeeItem.builder() + .typeMember(CoffeeType.LATTE) + .description(""" + A creamier, milk-based drink made with espresso. + A subtle coffee taste, with smooth texture. + High milk-to-coffee ratio. + """) + .build(), + CoffeeItem.builder() + .typeMember(CoffeeType.ESPRESSO) + .description(""" + A highly concentrated form of coffee, brewed under high pressure. + Syrupy, thick liquid in a small serving size. + Full bodied and intensely aromatic. + """) + .build() + ); + + @Override + public GetMenuOutput getMenu(GetMenuInput input, RequestContext context) { + return GetMenuOutput.builder().items(MENU).build(); + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/GetOrder.java b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/GetOrder.java new file mode 100644 index 0000000..6fde21e --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/GetOrder.java @@ -0,0 +1,39 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: MIT-0 + */ + +package io.smithy.kotlin.server.example; + +import io.smithy.kotlin.server.example.model.GetOrderInput; +import io.smithy.kotlin.server.example.model.GetOrderOutput; +import io.smithy.kotlin.server.example.model.OrderNotFound; +import io.smithy.kotlin.server.example.service.GetOrderOperation; +import java.util.UUID; +import java.util.logging.Logger; +import software.amazon.smithy.java.server.RequestContext; + +/** + * Returns the specified order if found. + */ +final class GetOrder implements GetOrderOperation { + private static final Logger LOGGER = Logger.getLogger(GetOrder.class.getName()); + + @Override + public GetOrderOutput getOrder(GetOrderInput input, RequestContext context) { + var order = OrderTracker.getOrderById(UUID.fromString(input.id())); + if (order == null) { + LOGGER.warning("Order not found: " + input.id()); + throw OrderNotFound.builder() + .orderId(input.id()) + .message("Order not found") + .build(); + } + LOGGER.info("Order " + input.id() + " found."); + return GetOrderOutput.builder() + .id(input.id()) + .coffeeType(order.type()) + .status(order.status()) + .build(); + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/Order.java b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/Order.java new file mode 100644 index 0000000..1e1fcb0 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/Order.java @@ -0,0 +1,19 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: MIT-0 + */ + +package io.smithy.kotlin.server.example; + +import io.smithy.kotlin.server.example.model.CoffeeType; +import io.smithy.kotlin.server.example.model.OrderStatus; +import java.util.UUID; + +/** + * A coffee drink order. + * + * @param id UUID of the order + * @param type Type of drink for the order + * @param status status of the order. + */ +public record Order(UUID id, CoffeeType type, OrderStatus status) {} diff --git a/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/OrderTracker.java b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/OrderTracker.java new file mode 100644 index 0000000..78ad17d --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/server/src/main/java/io/smithy/kotlin/server/example/OrderTracker.java @@ -0,0 +1,40 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: MIT-0 + */ + +package io.smithy.kotlin.server.example; + +import io.smithy.kotlin.server.example.model.OrderStatus; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** + * This class is a stand-in for a database. + */ +final class OrderTracker { + private static final Logger LOGGER = Logger.getLogger(OrderTracker.class.getName()); + private static final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); + private static final Map ORDERS = new ConcurrentHashMap<>(); + + public static void putOrder(Order order) { + ORDERS.put(order.id(), order); + + // Start a process to complete the order in the background. + executor.schedule(() -> completeOrder(order), 5, TimeUnit.SECONDS); + } + + private static void completeOrder(Order order) { + ORDERS.put(order.id(), new Order(order.id(), order.type(), OrderStatus.COMPLETED)); + LOGGER.info("Order completed: " + order.id()); + } + + public static Order getOrderById(UUID id) { + return ORDERS.get(id); + } +} + diff --git a/smithy-kotlin-examples/quickstart-kotlin/settings.gradle.kts b/smithy-kotlin-examples/quickstart-kotlin/settings.gradle.kts new file mode 100644 index 0000000..a9b2faf --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/settings.gradle.kts @@ -0,0 +1,20 @@ +rootProject.name = "smithy-kotlin-quickstart" + +pluginManagement { + val smithyGradleVersion = "1.3.0" + plugins { + id("software.amazon.smithy.gradle.smithy-jar").version(smithyGradleVersion) + id("software.amazon.smithy.gradle.smithy-base").version(smithyGradleVersion) + } + + repositories { + mavenLocal() + mavenCentral() + gradlePluginPortal() + } +} + +// Subprojects +include("client") +include("smithy") +include("server") diff --git a/smithy-kotlin-examples/quickstart-kotlin/smithy/build.gradle.kts b/smithy-kotlin-examples/quickstart-kotlin/smithy/build.gradle.kts new file mode 100644 index 0000000..2fa49d3 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/smithy/build.gradle.kts @@ -0,0 +1,21 @@ +description = "Smithy definition of a coffee shop service." + +plugins { + `java-library` + // Packages the models in this package into a jar for sharing/distribution by other packages + id("software.amazon.smithy.gradle.smithy-jar") +} + +dependencies { + // Adds the `@rpcv2Cbor` and `@restJson1` protocol traits + api(libs.smithy.aws.traits) +} + +// Helps the Smithy IntelliJ plugin identify models +sourceSets { + main { + java { + srcDir("model") + } + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/smithy/model/common.smithy b/smithy-kotlin-examples/quickstart-kotlin/smithy/model/common.smithy new file mode 100644 index 0000000..192c4f5 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/smithy/model/common.smithy @@ -0,0 +1,27 @@ +$version: "2" + +namespace com.example + +/// An enum describing the types of coffees available +enum CoffeeType { + DRIP + POUR_OVER + LATTE + ESPRESSO + COLD_BREW +} + +/// A structure which defines a coffee item which can be ordered +structure CoffeeItem { + /// A type of coffee + @required + type: CoffeeType + + @required + description: String +} + +/// A list of coffee items +list CoffeeItems { + member: CoffeeItem +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/smithy/model/main.smithy b/smithy-kotlin-examples/quickstart-kotlin/smithy/model/main.smithy new file mode 100644 index 0000000..13c994b --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/smithy/model/main.smithy @@ -0,0 +1,32 @@ +$version: "2" + +namespace com.example + +use aws.api#service +use aws.protocols#restJson1 +use smithy.protocols#rpcv2Cbor + +/// Allows users to retrieve a menu, create a coffee order, and +/// and to view the status of their orders +@title("Coffee Shop Service") +@restJson1 +@rpcv2Cbor +@service(sdkId: "CoffeeShop") +service CoffeeShop { + version: "2024-08-23" + operations: [ + GetMenu + ] + resources: [ + Order + ] +} + +/// Retrieve the menu +@http(method: "GET", uri: "/menu") +@readonly +operation GetMenu { + output := { + items: CoffeeItems + } +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/smithy/model/order.smithy b/smithy-kotlin-examples/quickstart-kotlin/smithy/model/order.smithy new file mode 100644 index 0000000..45d6264 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/smithy/model/order.smithy @@ -0,0 +1,83 @@ +$version: "2.0" + +namespace com.example + +/// An Order resource, which has an id and describes an order by the type of coffee +/// and the order's status +resource Order { + identifiers: { + id: Uuid + } + properties: { + coffeeType: CoffeeType + status: OrderStatus + } + read: GetOrder + create: CreateOrder +} + +/// Create an order +@idempotent +@http(method: "POST", uri: "/order") +operation CreateOrder { + input := for Order { + @required + $coffeeType + } + + output := for Order { + @required + $id + + @required + $coffeeType + + @required + $status + } +} + +/// Retrieve an order +@readonly +@http(method: "GET", uri: "/order/{id}") +operation GetOrder { + input := for Order { + @httpLabel + @required + $id + } + + output := for Order { + @required + $id + + @required + $coffeeType + + @required + $status + } + + errors: [ + OrderNotFound + ] +} + +/// An error indicating an order could not be found +@httpError(404) +@error("client") +structure OrderNotFound { + message: String + orderId: Uuid +} + +/// An identifier to describe a unique order +@length(min: 1, max: 128) +@pattern("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$") +string Uuid + +/// An enum describing the status of an order +enum OrderStatus { + IN_PROGRESS + COMPLETED +} diff --git a/smithy-kotlin-examples/quickstart-kotlin/smithy/smithy-build.json b/smithy-kotlin-examples/quickstart-kotlin/smithy/smithy-build.json new file mode 100644 index 0000000..703ffb7 --- /dev/null +++ b/smithy-kotlin-examples/quickstart-kotlin/smithy/smithy-build.json @@ -0,0 +1,3 @@ +{ + "version": "1.0" +} diff --git a/smithy-templates.json b/smithy-templates.json index 7cc3350..3559f26 100644 --- a/smithy-templates.json +++ b/smithy-templates.json @@ -180,6 +180,17 @@ ".gitattributes" ] }, + "smithy-kotlin-quickstart": { + "documentation": "Quickstart example for Smithy Kotlin", + "path": "smithy-kotlin-examples/quickstart-kotlin", + "include": [ + "gradle/", + "gradlew", + "gradlew.bat", + ".gitignore", + ".gitattributes" + ] + }, "docgen-cli": { "documentation": "Generate documentation using the smithy-docgen plugin.", "path": "smithy-docgen-examples/docgen-cli"