Smithy Go

repository·main·Indexed 42 days ago

https://github.com/aws/smithy-go

A toolset providing Smithy code generators for Go and the runtime packages required by generated code. It includes a Java/Gradle-based codegen plugin for creating Go clients and servers from Smithy models, as well as a runtime library featuring middleware, transport, and protocol support for various AWS and Smithy protocols. It is used by projects such as aws-sdk-go-v2.

Tokens
11.1K
Snippets
41
Records
57
Agent score
54%

What's inside Smithy Go

  1. Overview of Smithy Go components

    main

    Smithy Go consists of two primary components:

    1. Codegen: A Java/Gradle-based Smithy build plugin used to generate Go client, server, and shape code from Smithy models.
    2. Runtime (github.com/aws/smithy-go): The Go packages that the generated code depends on at runtime.

    Note: This repository does not contain pre-generated clients (like S3). It provides the tools to generate them from your own Smithy models.

  2. Understand the usage of Smithy Go Private packages

    main
    The private package collection contains packages used internally by Smithy Go. While these packages are not marked as internal (to allow them to be used as implementation details in generated code), they are subject to breaking changes without notice. Developers should treat them as unstable and avoid relying on them for long-term production stability.
  3. Build and test the codegen plugins

    main

    The codegen plugins are built and tested using Gradle from the codegen/ directory.

    To build and test:

    cd codegen && ./gradlew build

    To publish to your local Maven repository for downstream use:

    cd codegen && ./gradlew publishToMavenLocal
    # Build and test codegen
    cd codegen && ./gradlew build
    
    # Publish to local Maven for downstream use
    cd codegen && ./gradlew publishToMavenLocal
  4. Setup the Smithy Go codegen environment

    main

    To set up the Smithy Go code generators, ensure you have the correct versions of Java and Go installed, and use the provided Gradle wrapper to avoid version conflicts.

    Prerequisites:

    • Java 17: Required. Note that Java 14 is incompatible with Gradle 5.x. On macOS, if you have multiple versions, set your JAVA_HOME using: export JAVA_HOME=$(/usr/libexec/java_home -v 17).
    • Go 1.17: Required.
    • Gradle: Do not use brew install gradle as it installs Gradle 6.x, which is incompatible. Instead, use the ./gradlew script provided in the repository to automatically install the correct version.

    Setup Steps (from the smithy-go/codegen directory):

    1. Install Java 17 and Go 1.17.
    2. Run ./gradlew test to execute basic tests.
    3. To run codegen-specific tests, navigate to the test directory and use the relative path to the gradle wrapper: cd smithy-go-codegen-test; ../gradlew build.
    # Set JAVA_HOME on macOS if needed
    export JAVA_HOME=$(/usr/libexec/java_home -v 17)
    
    # Run basic tests
    ./gradlew test
    
    # Run codegen tests
    cd smithy-go-codegen-test
    ../gradlew build
  5. Generate a Go client from a Smithy model

    main

    To generate a Go client, apply the go-codegen plugin in your smithy-build.json file. You must specify the service Shape ID and the module name. You can optionally enable generateGoMod to create a default go.mod file and set a goDirective for the module's Go version.

    Requirements:

    • The smithy-go runtime requires a minimum version of Go 1.24.
    {
      "version": "1.0",
      "sources": [
        "models"
      ],
      "maven": {
        "dependencies": [
          "software.amazon.smithy.go:smithy-go-codegen:[0.1.0,2.0)"
        ]
      },
      "plugins": {
        "go-codegen": {
          "service": "example.weather#Weather",
          "module": "github.com/example/weather",
          "generateGoMod": true,
          "goDirective": "1.24"
        }
      }
    }
  6. Use the smithy package for Smithy SDK core components

    main
    The smithy package provides the foundational core components required to build or interact with a Smithy-based SDK. It serves as the base layer for Smithy implementations in Go.
  7. How ShapeSerializer and Serializable work together

    main

    Smithy uses a decoupled serialization pattern. Instead of encoding directly to a byte slice (like json.Marshaler), types implement the Serializable interface, which accepts a ShapeSerializer. This allows the same data structure to be serialized into different formats (e.g., JSON, XML, or HTTP headers) depending on the implementation of the serializer provided.

    Typically, a code-generated Serialize method will call WriteStruct, then call a helper method to serialize individual members, and finally call CloseStruct.

    // Example of how a generated type implements Serializable
    func (v *PutItemInput) Serialize(s smithy.ShapeSerializer) {
    	s.WriteStruct(schemas.PutItemInput)
    	v.SerializeMembers(s)
    	s.CloseStruct()
    }
    
    func (v *PutItemInput) SerializeMembers(s smithy.ShapeSerializer) {
    	if v.TableName != nil {
    		s.WriteString(schemas.PutItemInput_TableName, *v.TableName)
    	}
    	if v.Item != nil {
    		serializeAttributeMap(s, schemas.PutItemInput_Item, v.Item)
    	}
    }
  8. How OTEL attributes are propagated from smithy.Properties

    main

    When using Smithy tracing APIs, you can set key-value pairs in a smithy.Properties container. These pairs are automatically propagated to the underlying OTEL SDK.

    Supported Types

    The adapter natively supports the following attribute types (and their slice variants):

    • bool
    • int
    • int64
    • float64
    • string

    Key and Value Stringification

    If a key is a string and the value is one of the supported types above, it is passed directly. For other types, the adapter follows these rules:

    1. If the value implements the String() method, that value is used.
    2. Otherwise, the adapter uses the Go-string representation via fmt.Sprintf("%#v", ...).

    Example of key stringification behavior:

    type key struct{}
    func (k key) String() string { return "app.key" }
    
    type key2 struct{}
    // (No String() method)
    
    // Inside a tracing context:
    o.Properties.Set("app.version", "bar") // Result: ("app.version", "bar")
    o.Properties.Set(key{}, "baz")         // Result: ("app.key", "baz")
    o.Properties.Set(key2{}, "qux")        // Result: ("main.key2{}", "qux")
  9. Integrate OpenTelemetry tracing with Smithy clients

    main

    The smithyoteltracing package provides an adapter that allows you to use a standard OpenTelemetry (OTEL) Go SDK TracerProvider with Smithy-based clients (such as the AWS SDK for Go v2).

    To use it, call smithyoteltracing.Adapt(provider) and assign the result to the TracerProvider field in your client's options configuration.

    import (
    	"context"
    	"github.com/aws/aws-sdk-go-v2/config"
    	"github.com/aws/aws-sdk-go-v2/service/s3"
    	"github.com/aws/smithy-go/tracing/smithyoteltracing"
    	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
    	"go.opentelemetry.io/otel/sdk/trace"
    )
    
    func main() {
    	exporter, err := stdouttrace.New()
    	if err != nil {
    		panic(err)
    	}
    
    	cfg, err := config.LoadDefaultConfig(context.Background())
    	if err != nil {
    		panic(err)
    	}
    
    	// Create a standard OTEL TracerProvider
    	provider := trace.NewTracerProvider(trace.WithBatcher(exporter))
    
    	// Wrap the provider using Adapt() and pass it to the client options
    	svc := s3.NewFromConfig(cfg, func(o *s3.Options) {
    		o.TracerProvider = smithyoteltracing.Adapt(provider)
    	})
    	// ...
    }
  10. Integrate OpenTelemetry metrics with Smithy clients using Adapt

    main

    The smithyotelmetrics package provides an adapter to bridge the OpenTelemetry (OTEL) Go SDK with Smithy-based clients. To use it, call Adapt and pass in a concrete OTEL SDK MeterProvider. The resulting object can be assigned to the MeterProvider field in a Smithy client's options (e.g., in an AWS SDK for Go v2 service client).

    import (
    	"context"
    	"time"
    
    	"github.com/aws/aws-sdk-go-v2/config"
    	"github.com/aws/aws-sdk-go-v2/service/s3"
    	"github.com/aws/smithy-go/metrics/smithyotelmetrics"
    	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
    	"go.opentelemetry.io/otel/sdk/metric"
    )
    
    func main() {
    	ctx := context.Background()
    	cfg, err := config.LoadDefaultConfig(ctx)
    	if err != nil {
    		panic(err)
    	}
    
    	// 1. Setup an OTEL exporter (e.g., OTLP via HTTP)
    	exporter, err := otlpmetrichttp.New(ctx, otlpmetrichttp.WithEndpointURL("http://localhost:4318"))
    	if err != nil {
    		panic(err)
    	}
    
    	// 2. Create an OTEL MeterProvider with a periodic reader
    	reader := metric.NewPeriodicReader(exporter, metric.WithInterval(time.Second))
    	provider := metric.NewMeterProvider(metric.WithReader(reader))
    
    	// 3. Use smithyotelmetrics.Adapt to wrap the provider for the Smithy client
    	svc := s3.NewFromConfig(cfg, func(o *s3.Options) {
    		o.MeterProvider = smithyotelmetrics.Adapt(provider)
    	})
    	
    	_ = svc
    }
  11. Reference the `go-codegen` plugin settings

    main

    The go-codegen plugin (GAV: software.amazon.smithy.go:smithy-go-codegen) is used for Go client code generation. The following settings are available in smithy-build.json:

    SettingTypeRequiredDescription
    servicestringyesThe Shape ID of the service for which to generate the client.
    modulestringyesName of the module in generated.json (and go.mod if generateGoMod is enabled) and doc.go.
    generateGoModbooleanWhether to generate a default go.mod file. Default is false.
    goDirectivestringGo directive of the module. Default is the minimum supported Go version.
  12. Use standalone smithy-go modules

    main

    Some packages are published as independent Go modules with their own go.mod files. Use these for specific functionality without importing the entire runtime:

    • aws-http-auth: AWS SigV4/SigV4A HTTP signing.
    • tracing/smithyoteltracing: OpenTelemetry tracing adapter.
    • metrics/smithyotelmetrics: OpenTelemetry metrics adapter.