Skip to content

Add http-1x codegen support for server SDK generation#4376

Merged
drganjoo merged 9 commits intofeature/http-1.xfrom
fahadzub/http-1.x-codegen
Dec 10, 2025
Merged

Add http-1x codegen support for server SDK generation#4376
drganjoo merged 9 commits intofeature/http-1.xfrom
fahadzub/http-1.x-codegen

Conversation

@drganjoo
Copy link
Contributor

@drganjoo drganjoo commented Nov 2, 2025

This commit introduces comprehensive http-1x support to the server code generator,
enabling generation of server SDKs that work with either http@0.2.x or http@1.x
based on the http-1x codegen flag.

Key Changes

New Infrastructure

  • HttpDependencies.kt: New data class that ensures cohesive HTTP dependency
    selection, preventing accidental mixing of HTTP 0.x and 1.x versions. Provides
    helper methods for accessing HTTP types (Request, Response, HeaderMap, etc.)

  • MultiVersionTestFailure.kt: Test infrastructure for tracking failures by
    HTTP version, enabling tests to run against both http@0 and http@1

ServerCodegenConfig Updates

  • Add http1x boolean field to control HTTP version selection (config key: http-1x)
  • Defaults to false (http@0.2.x)

ServerCodegenContext Updates

  • Add isHttp1() method to check if http-1x is enabled
  • Add httpDependencies() method to provide version-appropriate HTTP dependencies
    throughout code generation

ServerRequiredCustomizations

  • Update to create and manage HttpDependencies based on http-1x setting
  • For http@0: use aws-smithy-legacy-http-server
  • For http@1: use aws-smithy-http-server

Protocol & Test Generator Updates

  • ServerProtocolTestGenerator: Support running protocol tests against both
    HTTP versions, with configurable test runtime mode (AS_CONFIGURED, BOTH, etc.)
  • ServerHttpBoundProtocolGenerator: Use HttpDependencies for all HTTP type
    references instead of hardcoded dependencies

Generator Updates

Updated generators to use HttpDependencies for type resolution:

  • ServerRootGenerator: Use httpDeps for dependency selection
  • ServerServiceGenerator: Pass HttpDependencies to child generators
  • ServerHttpSensitivityGenerator: Use httpDeps for HTTP types
  • ServerOperationGenerator, ServerBuilderGenerator: Use contextual HTTP deps

Test Infrastructure

  • ServerCodegenIntegrationTest: Add multi-version test support with
    ability to run tests against both HTTP versions
  • Http1xDependencyTest: New test validating correct dependency selection
    based on http-1x flag
  • Update existing tests to work with multi-version infrastructure

Core Changes

  • HttpBindingGenerator: Accept HttpDependencies parameter for version-appropriate
    type generation
  • EventStream generators: Use contextual HTTP dependencies
  • SmithyTypesPubUseExtra: Conditional imports based on HTTP version

Testing

All protocol tests can now run against both HTTP versions to ensure compatibility.
Tests track failures by HTTP version for easier debugging.

Relates to #3362

@drganjoo drganjoo requested review from a team as code owners November 2, 2025 20:12
Comment on lines +83 to +84
val httpDeps = HttpDependencies.create(settings.codegenConfig.http1x, rustSymbolProviderConfig.runtimeConfig)
EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.SERVER, httpDeps.smithyHttp)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would recommend that we actually make RuntimeConfig "do the right thing". Or make it so that you MUST pass an http version setting when getting the dependencies that depend on it.

You could incorporate the http1x setting into RuntimeConfig potentially, then make things like smithyHttp http version aware?

I'm worried that the way the code works right now will be somewhat confusing for folks to deal with and create these really confusing compilation errors.

class StatusCodeSensitivity(private val sensitive: Boolean, private val smithyHttpServer: RuntimeType) {
private val codegenScope =
arrayOf(
"SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should probably have ServerCargoDependency.smithyHttpServerAuto that automatically gives you the right one. I think the http version would actually fit pretty naturally into RuntimeConfig as an optional parameter.

Copy link
Collaborator

Choose a reason for hiding this comment

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

But if you just want to ship things like it is, I get that. I'm just kinda worried about the long term fallout of having it be non-centralized especially as we eventually try to get rid of the old codegen settings.

@drganjoo drganjoo force-pushed the fahadzub/http-1.x-codegen branch from 5c29232 to 9bb8f0d Compare December 3, 2025 14:07
@drganjoo drganjoo force-pushed the fahadzub/http-1.x-codegen branch from be0e38d to 13d6532 Compare December 8, 2025 13:58
Copy link
Collaborator

@rcoh rcoh left a comment

Choose a reason for hiding this comment

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

nice! this is pretty clean. Nice work on this—left a few small comments but its really just naming and other bits of my own confusion

/**
* HTTP version to use for code generation. Defaults to Http1x as that is the default for Clients..
*/
val httpVersion: HttpVersion = HttpVersion.Http1x,
Copy link
Collaborator

Choose a reason for hiding this comment

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

as long as there is a test somewhere this is fine, but I am a little bit worried about accidentally enabling this at some point

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, we have a test Http1xDependencyTest.kt.SDK defaults to http-1x disabled, and dependencies are correct that ensures by default http1x == false and the generated SDK correctly depends on http/hyper@0.

* For HTTP 1.x: returns http@1.x crate
* For HTTP 0.x: returns http@0.2.x crate
*/
fun httpForConfig(runtimeConfig: RuntimeConfig): RuntimeType =
Copy link
Collaborator

Choose a reason for hiding this comment

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

personally, I'd consider dropping the ForConfig on all of these. obviously doesn't really matter either way, or call them auto

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree. But there are already member variables with similar names without the suffix, for example, val Http. They are used in the codebase to directly reference Http 0.x/1.x libraries (particularly in tests where we need to test specific library versions). I'd like to rename those, for example, from val Http to val Http0x to make it explicit that callers are choosing a specific library version. However, I prefer to handle this renaming in a separate CR; otherwise, a lot more files will be included in this CR. I'll create a follow-up CR for this refactoring.

For now, this CR has the Auto as the suffix instead of ForConfig.

val HttpBodyUtil01x: CargoDependency =
CargoDependency("http-body-util", CratesIo("0.1.3"))

fun hyper(runtimeConfig: RuntimeConfig) =
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd name every conditional dependency auto so its easy to find and its obvious if it is giving an automatic version

service,
"$moduleName-http0x",
imports = imports,
extraCodegenConfig = extraCodegenConfig,
Copy link
Collaborator

Choose a reason for hiding this comment

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

consider setting http-1x: false explicitly so this still works when we change the default

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've done this deliberately as a safeguard to ensure that the default value of the flag is correct. If someone accidentally sets the http-1x flag to true, downstream tests, for example, codegen-server-test/eventstream/legacy would fail.

* @param extraCodegenConfig Optional additional codegen config (goes inside "codegen": {})
* @return List containing both http@0 (with -http0x suffix) and http@1 (no suffix) versions
*/
fun generateBothHttpVersions(
Copy link
Collaborator

Choose a reason for hiding this comment

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

consider making this an extension function on CodegenTest so you can do codegenTests.flatMap { it.bothHttpVersions() }. A little bit more obvious & flexible I think

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea - thanks.

})

let config = RpcV2CborServiceConfig::builder()
.layer(AddExtensionLayer::new(state.clone()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess cleaner? but seems like this is actually likely to be harder to debug for people?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but seems like this is actually likely to be harder to debug for people?

This approach matches our documentation. I wanted to have more sample points for AI tools to learn from.

Comment on lines +417 to +423
if (codegenContext.settings.runtimeConfig.httpVersion == HttpVersion.Http1x) {
rustWriter.rust(
"""
pub use crate::server::serve::serve;
""",
)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

not worth it here, but you can find an example in the client of doing automatic pub-use when a type is actually used

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah nice! I'll check the client code for future reference.

}

// Check if parallel execution is enabled via environment variable
val runInParallel = System.getenv("PARALLEL_HTTP_TESTS")?.toBoolean() ?: false
Copy link
Collaborator

Choose a reason for hiding this comment

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

actually used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, not at the moment. I had added this to speed up the CI, but haven't tested this with Github. I'll remove this for now.

@Test
fun `code compiles with custom validation exception using optionals`() {
serverIntegrationTest(completeTestModelWithOptionals)
serverIntegrationTest(completeTestModelWithOptionals, testCoverage = HttpTestType.AsConfigured)
Copy link
Collaborator

Choose a reason for hiding this comment

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

note in this context AsConfigured isn't obvious which one is going to get picked. Does this basically mean "the default?"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AsConfigured implies that serverIntegrationTest should not modify any settings and should use the codeGen flags as set by the caller. However, in practice, it has mostly been used for the default case. I'll rename it to Default to better reflect its actual usage.

return listOf(
// http@0 version (legacy) - no http-1x flag, add -http0x suffix
this.copy(
module = "${this.module}-http0x",
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't this set http-1x to false?

this.copy(
extraCodegenConfig =
if (this.extraCodegenConfig?.isNotEmpty() == true) {
""""http-1x": true, ${this.extraCodegenConfig}"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't this also produce a suffix?

@drganjoo drganjoo merged commit 3e8d03e into feature/http-1.x Dec 10, 2025
18 of 41 checks passed
@drganjoo drganjoo deleted the fahadzub/http-1.x-codegen branch December 10, 2025 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants