Skip to content

Add API Gateway Accept header customization#716

Open
Alan4506 wants to merge 1 commit into
smithy-lang:developfrom
Alan4506:feat/apigateway-accept-header
Open

Add API Gateway Accept header customization#716
Alan4506 wants to merge 1 commit into
smithy-lang:developfrom
Alan4506:feat/apigateway-accept-header

Conversation

@Alan4506

Copy link
Copy Markdown
Contributor

Context

While generating an API Gateway client from its model locally and running integration tests, several operations failed to deserialize their responses. For example, CreateRestApi returns a createdDate member modeled as a timestamp (epoch-seconds under restJson1), but the response returned an ISO-8601 string, so timestamp deserialization failed:

smithy_json._private.deserializers.JSONTokenError: Error parsing JSON.
Expected token of type `number` at path `createdDate`, but found: `string`: 2026-06-10T17:17:25Z

The root cause is API Gateway specific. Unless the client sends Accept: application/json, API Gateway responds with application/hal+json, in which timestamps are serialized as ISO-8601 strings instead of the epoch-seconds that the restJson1 protocol expects.

This is a documented API Gateway client requirement, not general protocol behavior. The Smithy spec calls it out as a service-specific customization: Amazon API Gateway Customizations. Other Smithy SDKs already implement this same customization in their codegen (e.g. smithy-rs, smithy-go, smithy-kotlin). This change adds the equivalent to smithy-python.

Changes

  • Runtime interceptor (smithy-aws-core): a new ApiGatewayAcceptHeaderInterceptor that sets Accept: application/json on every request in modify_before_signing.
  • Codegen integration (codegen/aws/core): a new ApiGatewayIntegration, registered with the PythonIntegration SPI. When the service being generated is API Gateway, it emits a plugin that registers the interceptor on the client; for all other services it does nothing. It lives under a new customizations/apigateway/ package, leaving room for the other service customizations the Smithy spec lists (e.g. Glacier, S3, Machine Learning).

Generated clients for the API Gateway service now include an accept_header.py plugin that appends the interceptor.

Testing

  • New unit tests (smithy-aws-core): verify the interceptor sets Accept: application/json, and that it overrides any pre-existing Accept header. Both pass.
  • Existing unit tests in smithy-aws-core still pass.
  • Regenerated the API Gateway client and confirmed the generated client.py registers the accept_header_plugin and that the plugin appends ApiGatewayAcceptHeaderInterceptor.
  • With the customization in place, the following script (AWS credentials must be set up first) can run without deserialization issue:
import asyncio

from aws_sdk_apigateway.client import APIGatewayClient
from aws_sdk_apigateway.config import Config
from aws_sdk_apigateway.models import CreateRestApiInput, DeleteRestApiInput
from smithy_aws_core.identity import EnvironmentCredentialsResolver

REGION = "us-east-1"


async def main() -> None:
    client = APIGatewayClient(
        config=Config(
            endpoint_uri=f"https://apigateway.{REGION}.amazonaws.com",
            region=REGION,
            aws_credentials_identity_resolver=EnvironmentCredentialsResolver(),
        )
    )

    # The response includes the `createdDate` timestamp member, which is what
    # fails to deserialize when API Gateway returns application/hal+json.
    created = await client.create_rest_api(
        input=CreateRestApiInput(name="accept-header-demo")
    )
    print(created.id, created.created_date)

    await client.delete_rest_api(input=DeleteRestApiInput(rest_api_id=created.id))


asyncio.run(main())

Without the customization this raises JSONTokenError: Expected token of type 'number' at path 'createdDate', but found: 'string'.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@Alan4506 Alan4506 requested a review from a team as a code owner June 10, 2026 18:09
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.

1 participant