Repository: Apicurio/apicurio-registry
Pull request #6087: feat(example): add go SDK example
Author: login: jsenko
Created: 2025-03-27T18:00:06Z | Merged: 2025-03-28T11:07:57Z



Diff:
diff --git a/examples/sdk/sdk-go/Makefile b/examples/sdk/sdk-go/Makefile
new file mode 100644
index 0000000000..eae23b63bd
--- /dev/null
+++ b/examples/sdk/sdk-go/Makefile
@@ -0,0 +1,8 @@
+build:
+	go fmt
+	go vet
+	go build -o bin/example main.go
+	chmod u+x bin/example
+
+clean:
+	rm -rf bin
diff --git a/examples/sdk/sdk-go/README.md b/examples/sdk/sdk-go/README.md
new file mode 100644
index 0000000000..acfba6709c
--- /dev/null
+++ b/examples/sdk/sdk-go/README.md
@@ -0,0 +1,27 @@
+# Go SDK Example
+
+1. Start Apicurio Registry 3 server, for example:
+
+```
+docker run --rm -it -p 8080:8080 quay.io/apicurio/apicurio-registry:latest
+```
+
+2. Build the example application (golang 1.23+ required):
+
+```
+make build
+```
+
+3. Run the example:
+
+```
+bin/example
+```
+
+Results in:
+
+```
+Server name: Apicurio Registry (In Memory)
+Server version: 3.0.6
+Created version 1 of artifact e98c1564-06a9-47fb-b551-ec4ec0cdf235
+```
diff --git a/examples/sdk/sdk-go/go.mod b/examples/sdk/sdk-go/go.mod
new file mode 100644
index 0000000000..0eeaa6e689
--- /dev/null
+++ b/examples/sdk/sdk-go/go.mod
@@ -0,0 +1,31 @@
+module github.com/Apicurio/apicurio-registry/examples/sdk/sdk-go
+
+go 1.23.0
+
+toolchain go1.24.1
+
+require (
+	github.com/apicurio/apicurio-registry/go-sdk v0.0.0-20241211181742-779f0994a1de // v3.0.6
+	github.com/microsoft/kiota-abstractions-go v1.9.1
+	github.com/microsoft/kiota-http-go v1.5.1
+)
+
+require (
+	github.com/cjlapao/common-go v0.0.48 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/microsoft/kiota-serialization-form-go v1.0.0 // indirect
+	github.com/microsoft/kiota-serialization-json-go v1.0.5 // indirect
+	github.com/microsoft/kiota-serialization-multipart-go v1.0.0 // indirect
+	github.com/microsoft/kiota-serialization-text-go v1.0.0 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/std-uritemplate/std-uritemplate/go/v2 v2.0.3 // indirect
+	github.com/stretchr/testify v1.10.0 // indirect
+	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+	go.opentelemetry.io/otel v1.35.0 // indirect
+	go.opentelemetry.io/otel/metric v1.35.0 // indirect
+	go.opentelemetry.io/otel/trace v1.35.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/examples/sdk/sdk-go/go.sum b/examples/sdk/sdk-go/go.sum
new file mode 100644
index 0000000000..877b5d169d
--- /dev/null
+++ b/examples/sdk/sdk-go/go.sum
@@ -0,0 +1,52 @@
+github.com/apicurio/apicurio-registry/go-sdk v0.0.0-20241211181742-779f0994a1de h1:JdmajE0M2KN3RUstGOzIT0xoRgf6xy9GJDMRp6xzr1A=
+github.com/apicurio/apicurio-registry/go-sdk v0.0.0-20241211181742-779f0994a1de/go.mod h1:zo80KCaFMf2/2rWjnhu8FkORVphgThsSBLlNAPHTyLI=
+github.com/cjlapao/common-go v0.0.48 h1:j2rMlSBoEG8P6WPV6aOoSHAWX6D9fl2jVpAqwnHKB4E=
+github.com/cjlapao/common-go v0.0.48/go.mod h1:wWif40/s6IIjaT+BO01Bo6VeYzz7IQ23BOj6xi/pAqw=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/microsoft/kiota-abstractions-go v1.9.1 h1:vkeluAj3ZLvOvG1NY5HcuBclhA9UXkXPeLxcBhQ28cU=
+github.com/microsoft/kiota-abstractions-go v1.9.1/go.mod h1:rlWmh9TR1j4EvkEp1Bz0rYTWunlvHDG9s6IMlkpDNrc=
+github.com/microsoft/kiota-http-go v1.5.1 h1:f260q6brp9/xHY4pECVPqzDYwoqieQhhcDiMMGc1ox0=
+github.com/microsoft/kiota-http-go v1.5.1/go.mod h1:r8HXDhMyLF4GJYdSmOGRquX3yI8KZpmbFCrTf78/kI0=
+github.com/microsoft/kiota-serialization-form-go v1.0.0 h1:UNdrkMnLFqUCccQZerKjblsyVgifS11b3WCx+eFEsAI=
+github.com/microsoft/kiota-serialization-form-go v1.0.0/go.mod h1:h4mQOO6KVTNciMF6azi1J9QB19ujSw3ULKcSNyXXOMA=
+github.com/microsoft/kiota-serialization-json-go v1.0.5 h1:DKLs/zcRlY+UrcmI8bCprqYeh3UKfbgbzwy/H2elrmM=
+github.com/microsoft/kiota-serialization-json-go v1.0.5/go.mod h1:SgAmhkzRPX1cjnzEWTv988IcBet7wbr4y6y014l5Y1w=
+github.com/microsoft/kiota-serialization-multipart-go v1.0.0 h1:3O5sb5Zj+moLBiJympbXNaeV07K0d46IfuEd5v9+pBs=
+github.com/microsoft/kiota-serialization-multipart-go v1.0.0/go.mod h1:yauLeBTpANk4L03XD985akNysG24SnRJGaveZf+p4so=
+github.com/microsoft/kiota-serialization-text-go v1.0.0 h1:XOaRhAXy+g8ZVpcq7x7a0jlETWnWrEum0RhmbYrTFnA=
+github.com/microsoft/kiota-serialization-text-go v1.0.0/go.mod h1:sM1/C6ecnQ7IquQOGUrUldaO5wj+9+v7G2W3sQ3fy6M=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
+github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
+github.com/std-uritemplate/std-uritemplate/go/v2 v2.0.3 h1:7hth9376EoQEd1hH4lAp3vnaLP2UMyxuMMghLKzDHyU=
+github.com/std-uritemplate/std-uritemplate/go/v2 v2.0.3/go.mod h1:Z5KcoM0YLC7INlNhEezeIZ0TZNYf7WSNO0Lvah4DSeQ=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
+go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
+go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
+go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
+go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
+go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
+go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/examples/sdk/sdk-go/main.go b/examples/sdk/sdk-go/main.go
new file mode 100644
index 0000000000..787cd08c60
--- /dev/null
+++ b/examples/sdk/sdk-go/main.go
@@ -0,0 +1,110 @@
+package main
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	registry3 "github.com/apicurio/apicurio-registry/go-sdk/pkg/registryclient-v3"
+	"github.com/apicurio/apicurio-registry/go-sdk/pkg/registryclient-v3/models"
+	kiotaAuth "github.com/microsoft/kiota-abstractions-go/authentication"
+	kiotaHttp "github.com/microsoft/kiota-http-go"
+	"regexp"
+)
+
+func initClient(registryUrl *string) *registry3.ApiClient {
+	prefix, err := regexp.Compile("^https?://.*")
+	if err != nil {
+		panic("Unexpected error: " + err.Error())
+	}
+	if !prefix.MatchString(*registryUrl) {
+		s := "http://" + *registryUrl
+		registryUrl = &s
+	}
+	suffix, err := regexp.Compile(".*/apis/registry/v3/?")
+	if err != nil {
+		panic("Unexpected error: " + err.Error())
+	}
+	if !suffix.MatchString(*registryUrl) {
+		s := *registryUrl + "/apis/registry/v3"
+		registryUrl = &s
+	}
+
+	// Compression is not currently supported by the Apicurio Registry server.
+	httpClient := kiotaHttp.GetDefaultClient(
+		kiotaHttp.NewRetryHandler(),
+		kiotaHttp.NewRedirectHandler(),
+		kiotaHttp.NewParametersNameDecodingHandler(),
+		kiotaHttp.NewCompressionHandlerWithOptions(kiotaHttp.NewCompressionOptions(false)),
+		kiotaHttp.NewUserAgentHandler(),
+		kiotaHttp.NewHeadersInspectionHandler(),
+	)
+
+	/*
+		middleware, err := kiotaHttp.GetDefaultMiddlewaresWithOptions(kiotaHttp.NewCompressionOptions(false))
+		if err != nil {
+			// panic: Unexpected error: unsupported option type
+			panic("Unexpected error: " + err.Error())
+		}
+		httpClient := kiotaHttp.GetDefaultClient(middleware...)
+	*/
+
+	adapter, err := kiotaHttp.NewNetHttpRequestAdapterWithParseNodeFactoryAndSerializationWriterFactoryAndHttpClient(
+		&kiotaAuth.AnonymousAuthenticationProvider{}, nil, nil, httpClient,
+	)
+	if err != nil {
+		panic("Unexpected error: " + err.Error())
+	}
+	adapter.SetBaseUrl(*registryUrl)
+
+	return registry3.NewApiClient(adapter)
+}
+
+func getServerInfo(client *registry3.ApiClient) {
+	res, err := client.System().Info().Get(context.Background(), nil)
+	if res != nil {
+		fmt.Printf("Server name: %s\n", *res.GetName())
+		fmt.Printf("Server version: %s\n", *res.GetVersion())
+	} else {
+		handleError(err)
+	}
+}
+
+func createNewArtifactVersion(client *registry3.ApiClient) {
+	newContent := models.NewVersionContent()
+	content := `{"openapi": "3.0.0", "info": {"title": "My API", "version": "1.0.0"}, "paths": {}}`
+	newContent.SetContent(&content)
+	contentType := "application/json"
+	newContent.SetContentType(&contentType)
+
+	newVersion := models.NewCreateVersion()
+	newVersion.SetContent(newContent)
+
+	newArtifact := models.NewCreateArtifact()
+	newArtifact.SetFirstVersion(newVersion)
+
+	res, err := client.Groups().ByGroupId("default").Artifacts().Post(context.Background(), newArtifact, nil)
+	if res != nil {
+		fmt.Printf("Created version %s of artifact %s\n", *res.GetVersion().GetVersion(), *res.GetVersion().GetArtifactId())
+	} else {
+		handleError(err)
+	}
+}
+
+func handleError(err error) {
+	if err == nil {
+		panic("No error value")
+	}
+	if details, ok := err.(*models.ProblemDetails); ok {
+		fmt.Printf("Server error: %s\n", *details.GetDetail())
+	} else {
+		fmt.Printf("Unknown error: %s\n", err.Error())
+	}
+}
+
+func main() {
+	registryUrl := flag.String("url", "http://localhost:8080", "URL of the Apicurio Registry 3 server")
+	flag.Parse()
+	client := initClient(registryUrl)
+	getServerInfo(client)
+	createNewArtifactVersion(client)
+}


Reviews:
user: login: jsenko
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-27T18:01:11Z
user: login: jsenko
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-27T18:06:20Z
user: login: EricWittmann
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-28T11:02:03Z

Review comments:
diff_hunk: @@ -0,0 +1,110 @@
+package main
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	registry3 "github.com/apicurio/apicurio-registry/go-sdk/pkg/registryclient-v3"
+	"github.com/apicurio/apicurio-registry/go-sdk/pkg/registryclient-v3/models"
+	kiotaAuth "github.com/microsoft/kiota-abstractions-go/authentication"
+	kiotaHttp "github.com/microsoft/kiota-http-go"
+	"regexp"
+)
+
+func initClient(registryUrl *string) *registry3.ApiClient {
+	prefix, err := regexp.Compile("^https?://.*")
+	if err != nil {
+		panic("Unexpected error: " + err.Error())
+	}
+	if !prefix.MatchString(*registryUrl) {
+		s := "http://" + *registryUrl
+		registryUrl = &s
+	}
+	suffix, err := regexp.Compile(".*/apis/registry/v3/?")
+	if err != nil {
+		panic("Unexpected error: " + err.Error())
+	}
+	if !suffix.MatchString(*registryUrl) {
+		s := *registryUrl + "/apis/registry/v3"
+		registryUrl = &s
+	}
+
+	// Compression is not currently supported by the Apicurio Registry server.
+	httpClient := kiotaHttp.GetDefaultClient(
+		kiotaHttp.NewRetryHandler(),
+		kiotaHttp.NewRedirectHandler(),
+		kiotaHttp.NewParametersNameDecodingHandler(),
+		kiotaHttp.NewCompressionHandlerWithOptions(kiotaHttp.NewCompressionOptions(false)),
+		kiotaHttp.NewUserAgentHandler(),
+		kiotaHttp.NewHeadersInspectionHandler(),
+	)
+
+	/*
path: examples/sdk/sdk-go/main.go
user: login: jsenko
body: Keep this for now, I want to report an issue that I've encountered to Kiota.
created_at: 2025-03-27T18:01:11Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,33 @@
+module github.com/Apicurio/apicurio-registry/examples/sdk/sdk-go
+
+go 1.23.0
+
+toolchain go1.24.1
+
+//toolchain go1.24.1
+
+require (
+	github.com/apicurio/apicurio-registry/go-sdk v0.0.0-20241211181742-779f0994a1de // v3.0.6
path: examples/sdk/sdk-go/go.mod
user: login: jsenko
body: TODO: We have to change the go-sdk module name, see https://go.dev/doc/modules/version-numbers#major-version . 
created_at: 2025-03-27T18:06:20Z
author_association: MEMBER

PR comments:
user: login: jsenko
created_at: 2025-03-27T18:00:27Z
body: I'll update the blog post next.
author_association: MEMBER
user: login: jsenko
created_at: 2025-03-27T18:12:22Z
body: @EricWittmann I have a quick question: Since go is the only SDK that must keep the generated code in the repo, do we have a workflow that updates or checks the generated code on `main`? I've seen you've done an update here https://github.com/Apicurio/apicurio-registry/pull/6065 but is that checked? It reminds me of the situation with operator install file.
author_association: MEMBER