From b7f1a5793f43bb52b7e13bcb1b8567da12582bea Mon Sep 17 00:00:00 2001 From: 82marbag <69267416+82marbag@users.noreply.github.com> Date: Fri, 2 Dec 2022 12:10:26 -0500 Subject: [PATCH] Fix service builder docs (#2046) * Fix doc prefix in service generator * Move documentation to root module * Documentation improvements * Expose handler imports Signed-off-by: Daniele Ahmed Co-authored-by: Harry Barber --- .../smithy/generators/DocHandlerGenerator.kt | 46 ++++- .../ServerOperationShapeGenerator.kt | 2 +- .../generators/ServerServiceGenerator.kt | 193 ++++++++++++++++++ .../generators/ServerServiceGeneratorV2.kt | 148 +------------- 4 files changed, 232 insertions(+), 157 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt index d4e4affccd..38796a2eb8 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt @@ -9,6 +9,7 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget @@ -22,19 +23,39 @@ import software.amazon.smithy.rust.codegen.core.util.outputShape /** Generates a stub for use within documentation. */ -class DocHandlerGenerator(private val operation: OperationShape, private val commentToken: String = "//", private val handlerName: String, codegenContext: CodegenContext) { +class DocHandlerGenerator( + codegenContext: CodegenContext, + private val operation: OperationShape, + private val handlerName: String, + private val commentToken: String = "//", +) { private val model = codegenContext.model private val symbolProvider = codegenContext.symbolProvider private val crateName = codegenContext.moduleUseName() + private val inputSymbol = symbolProvider.toSymbol(operation.inputShape(model)) + private val outputSymbol = symbolProvider.toSymbol(operation.outputShape(model)) + private val errorSymbol = operation.errorSymbol(model, symbolProvider, CodegenTarget.SERVER) + + /** + * Returns the imports required for the function signature + */ + fun docSignatureImports(): Writable = writable { + if (operation.errors.isNotEmpty()) { + rust("$commentToken use $crateName::${ErrorsModule.name}::${errorSymbol.name};") + } + rust( + """ + $commentToken use $crateName::${InputsModule.name}::${inputSymbol.name}; + $commentToken use $crateName::${OutputsModule.name}::${outputSymbol.name}; + """.trimIndent(), + ) + } + /** * Returns the function signature for an operation handler implementation. Used in the documentation. */ fun docSignature(): Writable { - val inputSymbol = symbolProvider.toSymbol(operation.inputShape(model)) - val outputSymbol = symbolProvider.toSymbol(operation.outputShape(model)) - val errorSymbol = operation.errorSymbol(model, symbolProvider, CodegenTarget.SERVER) - val outputT = if (operation.errors.isEmpty()) { outputSymbol.name } else { @@ -42,13 +63,8 @@ class DocHandlerGenerator(private val operation: OperationShape, private val com } return writable { - if (operation.errors.isNotEmpty()) { - rust("$commentToken ## use $crateName::${ErrorsModule.name}::${errorSymbol.name};") - } rust( """ - $commentToken ## use $crateName::${InputsModule.name}::${inputSymbol.name}; - $commentToken ## use $crateName::${OutputsModule.name}::${outputSymbol.name}; $commentToken async fn $handlerName(input: ${inputSymbol.name}) -> $outputT { $commentToken todo!() $commentToken } @@ -58,6 +74,14 @@ class DocHandlerGenerator(private val operation: OperationShape, private val com } fun render(writer: RustWriter) { - docSignature()(writer) + writer.rustTemplate( + """ + #{Docs:W} + $commentToken + #{Handler:W} + """, + "Docs" to docSignatureImports(), + "Handler" to docSignature(), + ) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationShapeGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationShapeGenerator.kt index c8bdffe739..7e201c3367 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationShapeGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationShapeGenerator.kt @@ -63,7 +63,7 @@ class ServerOperationShapeGenerator( "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(codegenContext.runtimeConfig).toType(), "Tower" to ServerCargoDependency.Tower.toType(), - "Handler" to DocHandlerGenerator(operations[0], "//!", "handler", codegenContext)::render, + "Handler" to DocHandlerGenerator(codegenContext, operations[0], "handler", "//!")::render, ) for (operation in operations) { ServerOperationGenerator(codegenContext, operation).render(writer) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 57744a5789..c8bcb5250f 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -10,12 +10,21 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustModule +import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility +import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.rustlang.join import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext +import software.amazon.smithy.rust.codegen.core.smithy.ErrorsModule +import software.amazon.smithy.rust.codegen.core.smithy.InputsModule +import software.amazon.smithy.rust.codegen.core.smithy.OutputsModule import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport +import software.amazon.smithy.rust.codegen.core.util.toSnakeCase +import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolGenerator import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolTestGenerator @@ -37,12 +46,196 @@ open class ServerServiceGenerator( protected val operations = index.getContainedOperations(codegenContext.serviceShape).sortedBy { it.id } private val serviceName = codegenContext.serviceShape.id.name.toString() + fun documentation(writer: RustWriter) { + val operations = index.getContainedOperations(codegenContext.serviceShape).toSortedSet(compareBy { it.id }) + val builderFieldNames = + operations.associateWith { RustReservedWords.escapeIfNeeded(codegenContext.symbolProvider.toSymbol(it).name.toSnakeCase()) } + .toSortedMap( + compareBy { it.id }, + ) + val crateName = codegenContext.moduleUseName() + val builderName = "${serviceName}Builder" + val service = codegenContext.serviceShape + val hasErrors = service.operations.any { codegenContext.model.expectShape(it).asOperationShape().get().errors.isNotEmpty() } + val handlers: Writable = operations + .map { operation -> + DocHandlerGenerator(codegenContext, operation, builderFieldNames[operation]!!, "//!")::render + } + .join("//!\n") + + writer.rustTemplate( + """ + //! A fast and customizable Rust implementation of the $serviceName Smithy service. + //! + //! ## Using $serviceName + //! + //! The primary entrypoint is [`$serviceName`]: it satisfies the [`Service`] + //! trait and therefore can be handed to a [`hyper` server] via [`$serviceName::into_make_service`] or used in Lambda via [`LambdaHandler`](#{SmithyHttpServer}::routing::LambdaHandler). + //! The [`crate::${InputsModule.name}`], ${if (!hasErrors) "and " else ""}[`crate::${OutputsModule.name}`], ${if (hasErrors) "and [`crate::${ErrorsModule.name}`]" else "" } + //! modules provide the types used in each operation. + //! + //! ###### Running on Hyper + //! + //! ```rust,no_run + //! ## use std::net::SocketAddr; + //! ## async fn dummy() { + //! use $crateName::$serviceName; + //! + //! ## let app = $serviceName::builder_without_plugins().build_unchecked(); + //! let server = app.into_make_service(); + //! let bind: SocketAddr = "127.0.0.1:6969".parse() + //! .expect("unable to parse the server bind address and port"); + //! hyper::Server::bind(&bind).serve(server).await.unwrap(); + //! ## } + //! ``` + //! + //! ###### Running on Lambda + //! + //! This requires the `aws-lambda` feature flag to be passed to the [`#{SmithyHttpServer}`] crate. + //! + //! ```rust,ignore + //! use #{SmithyHttpServer}::routing::LambdaHandler; + //! use $crateName::$serviceName; + //! + //! ## async fn dummy() { + //! ## let app = $serviceName::builder_without_plugins().build_unchecked(); + //! let handler = LambdaHandler::new(app); + //! lambda_http::run(handler).await.unwrap(); + //! ## } + //! ``` + //! + //! ## Building the $serviceName + //! + //! To construct [`$serviceName`] we use [`$builderName`] returned by [`$serviceName::builder_without_plugins`] + //! or [`$serviceName::builder_with_plugins`]. + //! + //! #### Plugins + //! + //! The [`$serviceName::builder_with_plugins`] method, returning [`$builderName`], + //! accepts a [`Plugin`](aws_smithy_http_server::plugin::Plugin). + //! Plugins allow you to build middleware which is aware of the operation it is being applied to. + //! + //! ```rust + //! ## use #{SmithyHttpServer}::plugin::IdentityPlugin as LoggingPlugin; + //! ## use #{SmithyHttpServer}::plugin::IdentityPlugin as MetricsPlugin; + //! ## use hyper::Body; + //! use #{SmithyHttpServer}::plugin::PluginPipeline; + //! use $crateName::{$serviceName, $builderName}; + //! + //! let plugins = PluginPipeline::new() + //! .push(LoggingPlugin) + //! .push(MetricsPlugin); + //! let builder: $builderName = $serviceName::builder_with_plugins(plugins); + //! ``` + //! + //! Check out [`#{SmithyHttpServer}::plugin`] to learn more about plugins. + //! + //! #### Handlers + //! + //! [`$builderName`] provides a setter method for each operation in your Smithy model. The setter methods expect an async function as input, matching the signature for the corresponding operation in your Smithy model. + //! We call these async functions **handlers**. This is where your application business logic lives. + //! + //! Every handler must take an `Input`, and optional [`extractor arguments`](#{SmithyHttpServer}::request), while returning: + //! + //! * A `Result` if your operation has modeled errors, or + //! * An `Output` otherwise. + //! + //! ```rust + //! ## struct Input; + //! ## struct Output; + //! ## struct Error; + //! async fn infallible_handler(input: Input) -> Output { todo!() } + //! + //! async fn fallible_handler(input: Input) -> Result { todo!() } + //! ``` + //! + //! Handlers can accept up to 8 extractors: + //! + //! ```rust + //! ## struct Input; + //! ## struct Output; + //! ## struct Error; + //! ## struct State; + //! ## use std::net::SocketAddr; + //! use #{SmithyHttpServer}::request::{extension::Extension, connect_info::ConnectInfo}; + //! + //! async fn handler_with_no_extensions(input: Input) -> Output { + //! todo!() + //! } + //! + //! async fn handler_with_one_extractor(input: Input, ext: Extension) -> Output { + //! todo!() + //! } + //! + //! async fn handler_with_two_extractors( + //! input: Input, + //! ext0: Extension, + //! ext1: ConnectInfo, + //! ) -> Output { + //! todo!() + //! } + //! ``` + //! + //! See the [`operation module`](#{SmithyHttpServer}::operation) for information on precisely what constitutes a handler. + //! + //! #### Build + //! + //! You can convert [`$builderName`] into [`$serviceName`] using either [`$builderName::build`] or [`$builderName::build_unchecked`]. + //! + //! [`$builderName::build`] requires you to provide a handler for every single operation in your Smithy model. It will return an error if that is not the case. + //! + //! [`$builderName::build_unchecked`], instead, does not require exhaustiveness. The server will automatically return 500 Internal Server Error to all requests for operations that do not have a registered handler. + //! [`$builderName::build_unchecked`] is particularly useful if you are deploying your Smithy service as a collection of Lambda functions, where each Lambda is only responsible for a subset of the operations in the Smithy service (or even a single one!). + //! + //! ## Example + //! + //! ```rust + //! ## use std::net::SocketAddr; + //! use $crateName::$serviceName; + //! + //! ##[tokio::main] + //! pub async fn main() { + //! let app = $serviceName::builder_without_plugins() + ${builderFieldNames.values.joinToString("\n") { "//! .$it($it)" }} + //! .build() + //! .expect("failed to build an instance of $serviceName"); + //! + //! let bind: SocketAddr = "127.0.0.1:6969".parse() + //! .expect("unable to parse the server bind address and port"); + //! let server = hyper::Server::bind(&bind).serve(app.into_make_service()); + //! ## let server = async { Ok::<_, ()>(()) }; + //! + //! // Run your service! + //! if let Err(err) = server.await { + //! eprintln!("server error: {:?}", err); + //! } + //! } + //! + #{Handlers:W} + //! + //! ``` + //! + //! [`serve`]: https://docs.rs/hyper/0.14.16/hyper/server/struct.Builder.html##method.serve + //! [`tower::make::MakeService`]: https://docs.rs/tower/latest/tower/make/trait.MakeService.html + //! [HTTP binding traits]: https://smithy.io/2.0/spec/http-bindings.html + //! [operations]: https://smithy.io/2.0/spec/service-types.html##operation + //! [hyper server]: https://docs.rs/hyper/latest/hyper/server/index.html + //! [Service]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html + """, + "Handlers" to handlers, + "ExampleHandler" to operations.take(1).map { operation -> DocHandlerGenerator(codegenContext, operation, builderFieldNames[operation]!!, "//!").docSignature() }, + "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(codegenContext.runtimeConfig).toType(), + ) + } + /** * Render Service Specific code. Code will end up in different files via [useShapeWriter]. See `SymbolVisitor.kt` * which assigns a symbol location to each shape. */ fun render() { rustCrate.lib { + documentation(this) + rust("##[doc(inline, hidden)]") rust("pub use crate::service::{$serviceName, ${serviceName}Builder, MissingOperationsError};") } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 28fcdafd1d..e0c852b6e7 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -17,9 +17,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext -import software.amazon.smithy.rust.codegen.core.smithy.ErrorsModule -import software.amazon.smithy.rust.codegen.core.smithy.InputsModule -import software.amazon.smithy.rust.codegen.core.smithy.OutputsModule import software.amazon.smithy.rust.codegen.core.util.toPascalCase import software.amazon.smithy.rust.codegen.core.util.toSnakeCase import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency @@ -42,7 +39,7 @@ class ServerServiceGeneratorV2( ) private val model = codegenContext.model private val symbolProvider = codegenContext.symbolProvider - val crateName = codegenContext.settings.moduleName.toSnakeCase() + private val crateName = codegenContext.moduleUseName() private val service = codegenContext.serviceShape private val serviceName = service.id.name.toPascalCase() @@ -159,7 +156,7 @@ class ServerServiceGeneratorV2( } """, "Protocol" to protocol.markerStruct(), - "Handler" to DocHandlerGenerator(operationShape, "///", "handler", codegenContext)::render, + "Handler" to DocHandlerGenerator(codegenContext, operationShape, "handler", "///")::render, *codegenScope, ) @@ -259,7 +256,7 @@ class ServerServiceGeneratorV2( rustTemplate( """ /// Constructs a [`$serviceName`] from the arguments provided to the builder. - /// Operations without a handler default to returning 500s to the caller. + /// Operations without a handler default to returning 500 Internal Server Error to the caller. /// /// Check out [`$builderName::build`] if you'd prefer the builder to fail if one or more operations do /// not have a registered handler. @@ -474,145 +471,8 @@ class ServerServiceGeneratorV2( } fun render(writer: RustWriter) { - val crateName = codegenContext.moduleUseName() - val handlers: Writable = operations - .map { operation -> - DocHandlerGenerator(operation, "///", builderFieldNames[operation]!!, codegenContext).docSignature() - } - .reduce { acc, wt -> - writable { - rustTemplate("#{acc:W} \n#{wt:W}", "acc" to acc, "wt" to wt) - } - } - - val hasErrors = service.operations.any { model.expectShape(it).asOperationShape().get().errors.isNotEmpty() } - writer.rustTemplate( """ - /// A fast and customizable Rust implementation of the $serviceName Smithy service. - /// - /// ## Using $serviceName - /// - /// The primary entrypoint is [`$serviceName`]: it satisfies the [`Service`] - /// trait and therefore can be handed to a [`hyper` server] via [`$serviceName::into_make_service`] or used in Lambda via [`#{SmithyHttpServer}::routing::LambdaHandler`]. - /// The [`crate::${InputsModule.name}`], ${if (!hasErrors) "and " else ""}[`crate::${OutputsModule.name}`], ${if (hasErrors) "and [`crate::${ErrorsModule.name}`]" else "" } - /// modules provide the types used in each operation. - /// - /// ###### Running on Hyper - /// ```rust,no_run - /// ## use $crateName::$serviceName; - /// ## use std::net::SocketAddr; - /// ## ##[tokio::main] - /// ## pub async fn main() { - /// ## let app = $serviceName::builder_without_plugins().build_unchecked(); - /// let server = app.into_make_service(); - /// let bind: SocketAddr = "127.0.0.1:6969".parse() - /// .expect("unable to parse the server bind address and port"); - /// hyper::Server::bind(&bind).serve(server).await.unwrap(); - /// ## } - /// ``` - /// ###### Running on Lambda - /// ```rust,ignore - /// ## use $crateName::$serviceName; - /// ## ##[tokio::main] - /// ## pub async fn main() { - /// ## let app = $serviceName::builder_without_plugins().build_unchecked(); - /// let handler = #{SmithyHttpServer}::routing::LambdaHandler::new(app); - /// lambda_http::run(handler).await.unwrap(); - /// ## } - /// ``` - /// - /// ## Building the $serviceName - /// - /// To construct [`$serviceName`] we use [`$builderName`] returned by [`$serviceName::builder_without_plugins`] - /// or [`$serviceName::builder_with_plugins`]. - /// - /// #### Plugins - /// - /// The [`$serviceName::builder_with_plugins`] method, returning [`$builderName`], - /// accepts a [`Plugin`](aws_smithy_http_server::plugin::Plugin). - /// Plugins allow you to build middleware which is aware of the operation it is being applied to. - /// - /// ```rust,ignore - /// ## use #{SmithyHttpServer}::plugin::IdentityPlugin as LoggingPlugin; - /// ## use #{SmithyHttpServer}::plugin::IdentityPlugin as MetricsPlugin; - /// ## use #{SmithyHttpServer}::plugin::PluginPipeline; - /// let plugins = PluginPipeline::new() - /// .push(LoggingPlugin) - /// .push(MetricsPlugin); - /// let builder = $crateName::$serviceName::builder_with_plugins(plugins); - /// ``` - /// - /// Check out [`#{SmithyHttpServer}::plugin`] to learn more about plugins. - /// - /// #### Handlers - /// - /// [`$builderName`] provides a setter method for each operation in your Smithy model. The setter methods expect an async function as input, matching the signature for the corresponding operation in your Smithy model. - /// We call these async functions **handlers**. This is where your application business logic lives. - /// - /// Every handler must take an `Input`, and optional [`extractor arguments`](#{SmithyHttpServer}::request), while returning: - /// - /// * A `Result` if your operation has modeled errors, or - /// * An `Output` otherwise. - /// - /// ```rust,ignore - /// async fn fallible_handler(input: Input, extensions: #{SmithyHttpServer}::Extension) -> Result { todo!() } - /// async fn infallible_handler(input: Input, extensions: #{SmithyHttpServer}::Extension) -> Output { todo!() } - /// ``` - /// - /// Handlers can accept up to 8 extractors: - /// - /// ```rust,ignore - /// async fn handler_with_no_extensions(input: Input) -> ... { todo!() } - /// async fn handler_with_one_extension(input: Input, ext: #{SmithyHttpServer}::Extension) -> ... { todo!() } - /// async fn handler_with_two_extensions(input: Input, ext0: #{SmithyHttpServer}::Extension, ext1: #{SmithyHttpServer}::Extension) -> ... { todo!() } - /// ... - /// ``` - /// - /// #### Build - /// - /// You can convert [`$builderName`] into [`$serviceName`] using either [`$builderName::build`] or [`$builderName::build_unchecked`]. - /// - /// [`$builderName::build`] requires you to provide a handler for every single operation in your Smithy model. It will return an error if that is not the case. - /// - /// [`$builderName::build_unchecked`], instead, does not require exhaustiveness. The server will automatically return 500s to all requests for operations that do not have a registered handler. - /// [`$builderName::build_unchecked`] is particularly useful if you are deploying your Smithy service as a collection of Lambda functions, where each Lambda is only responsible for a subset of the operations in the Smithy service (or even a single one!). - /// - /// ## Example - /// - /// ```rust - /// use std::net::SocketAddr; - /// use $crateName::$serviceName; - /// - /// ##[tokio::main] - /// pub async fn main() { - /// let app = $serviceName::builder_without_plugins() - ${builderFieldNames.values.joinToString("\n") { "/// .$it($it)" }} - /// .build() - /// .expect("failed to build an instance of $serviceName"); - /// - /// let bind: SocketAddr = "127.0.0.1:6969".parse() - /// .expect("unable to parse the server bind address and port"); - /// let server = hyper::Server::bind(&bind).serve(app.into_make_service()); - /// ## let server = async { Ok::<_, ()>(()) }; - /// - /// // Run your service! - /// if let Err(err) = server.await { - /// eprintln!("server error: {:?}", err); - /// } - /// } - /// - #{Handlers:W} - /// - /// ``` - /// - /// [`serve`]: https://docs.rs/hyper/0.14.16/hyper/server/struct.Builder.html##method.serve - /// [`tower::make::MakeService`]: https://docs.rs/tower/latest/tower/make/trait.MakeService.html - /// [HTTP binding traits]: https://smithy.io/2.0/spec/http-bindings.html - /// [operations]: https://smithy.io/2.0/spec/service-types.html##operation - /// [hyper server]: https://docs.rs/hyper/latest/hyper/server/index.html - /// [Service]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html - #{Builder:W} #{MissingOperationsError:W} @@ -625,8 +485,6 @@ class ServerServiceGeneratorV2( "MissingOperationsError" to missingOperationsError(), "RequestSpecs" to requestSpecsModule(), "Struct" to serviceStruct(), - "Handlers" to handlers, - "ExampleHandler" to operations.take(1).map { operation -> DocHandlerGenerator(operation, "///", builderFieldNames[operation]!!, codegenContext).docSignature() }, *codegenScope, ) }