Skip to content

Commit 944dad4

Browse files
committed
Client: Add compatibility mode, tests, config option and documentation
1 parent 21aa9d5 commit 944dad4

5 files changed

+83
-5
lines changed

.doc/connecting.asciidoc

+13
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ cfg := elasticsearch.Config{
6060
es, err := elasticsearch.NewClient(cfg)
6161
------------------------------------
6262

63+
[discrete]
64+
[[compatibility-mode]]
65+
==== Compatibility Mode
66+
67+
Elasticsearch server 8.0 introduces a new compatibility mode allowing for a smoother transition from 7 to 8.
68+
Using the compatibility mode, the client sends versioned headers with each request instructing the server on the expected behaviour.
69+
------------------------------------
70+
Content-Type: application/vnd.elasticsearch+json; compatible-with=7
71+
Accept: application/vnd.elasticsearch+json; compatible-with=7
72+
------------------------------------
73+
This allows you to update the server first, then the client.
74+
75+
To enable this, the latest 7.x client can use the environment variable `ELASTIC_CLIENT_APIVERSIONING` or the configuration option `config.EnableCompatibilityMode` in the client Config.
6376

6477
[discrete]
6578
[[client-usage]]

elasticsearch.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@ type Config struct {
8282
EnableRetryOnTimeout bool // Default: false.
8383
MaxRetries int // Default: 3.
8484

85-
CompressRequestBody bool // Default: false.
85+
CompressRequestBody bool // Default: false.
86+
DiscoverNodesOnStart bool // Discover nodes when initializing the client. Default: false.
8687

87-
DiscoverNodesOnStart bool // Discover nodes when initializing the client. Default: false.
8888
DiscoverNodesInterval time.Duration // Discover nodes periodically. Default: disabled.
8989

90-
EnableMetrics bool // Enable the metrics collection.
91-
EnableDebugLogger bool // Enable the debug logging.
90+
EnableMetrics bool // Enable the metrics collection.
91+
EnableDebugLogger bool // Enable the debug logging.
92+
EnableCompatibilityMode bool // Enable sends compatibility header
9293

9394
DisableMetaHeader bool // Disable the additional "X-Elastic-Client-Meta" HTTP header.
9495
UseResponseCheckOnly bool
@@ -204,6 +205,7 @@ func NewClient(cfg Config) (*Client, error) {
204205
RetryBackoff: cfg.RetryBackoff,
205206

206207
CompressRequestBody: cfg.CompressRequestBody,
208+
CompatibilityHeader: cfg.EnableCompatibilityMode,
207209

208210
EnableMetrics: cfg.EnableMetrics,
209211
EnableDebugLogger: cfg.EnableDebugLogger,

elasticsearch_integration_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ func TestClientTransport(t *testing.T) {
158158
t.Fatalf("Expected net.OpError, but got: %T", err)
159159
}
160160
})
161+
162+
t.Run("Compatibility Header", func(t *testing.T) {
163+
client, err := elasticsearch.NewClient(elasticsearch.Config{EnableCompatibilityMode: true})
164+
if err != nil {
165+
t.Fatal(err)
166+
}
167+
168+
res, err := client.Info()
169+
if err != nil {
170+
t.Fatal(err)
171+
}
172+
173+
contentType := res.Header.Get("content-type")
174+
if contentType != "application/vnd.elasticsearch+json;compatible-with=7" {
175+
t.Fatalf("Unexpected content-type header, want \"application/vnd.elasticsearch+json;compatible-with=7\", got: %s", contentType)
176+
}
177+
})
161178
}
162179

163180
type CustomTransport struct {

elasticsearch_internal_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ func TestResponseCheckOnly(t *testing.T) {
696696
}
697697
}
698698

699+
699700
func TestProductCheckError(t *testing.T) {
700701
var requestPaths []string
701702
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -731,3 +732,45 @@ func TestProductCheckError(t *testing.T) {
731732
t.Fatalf("product check should be valid, got : %v", c.productCheckSuccess)
732733
}
733734
}
735+
736+
737+
func TestCompatibilityHeader(t *testing.T) {
738+
client, err := NewClient(Config{
739+
Transport: &mockTransp{RoundTripFunc: func(request *http.Request) (*http.Response, error) {
740+
if request.URL.Path == "/" || request.URL.Path == "/test-index/_search" {
741+
accept := request.Header.Get("Accept")
742+
if accept != "application/vnd.elasticsearch+json;compatible-with=7" {
743+
t.Fatalf("Invalid header, expected: %s, got: %s",
744+
"application/vnd.elasticsearch+json;compatible-with=7",
745+
accept,
746+
)
747+
}
748+
749+
if request.URL.Path == "/test-index/_search" {
750+
contentType := request.Header.Get("Content-Type")
751+
if contentType != "application/vnd.elasticsearch+json;compatible-with=7" {
752+
t.Fatalf("Invalid header, expected: %s, got: %s",
753+
"application/vnd.elasticsearch+json;compatible-with=7",
754+
contentType,
755+
)
756+
}
757+
}
758+
} else {
759+
t.Fatal("Unexpected route called")
760+
}
761+
762+
return defaultRoundTripFunc(request)
763+
}},
764+
Addresses: []string{"http://127.0.0.1:9200"},
765+
EnableCompatibilityMode: true,
766+
})
767+
if err != nil {
768+
t.Fatal(err)
769+
}
770+
771+
client.Info()
772+
client.Search(
773+
client.Search.WithIndex("test-index"),
774+
client.Search.WithBody(strings.NewReader("{}")),
775+
)
776+
}

estransport/estransport.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ type Config struct {
9292
RetryBackoff func(attempt int) time.Duration
9393

9494
CompressRequestBody bool
95+
CompatibilityHeader bool
9596

9697
EnableMetrics bool
9798
EnableDebugLogger bool
@@ -129,6 +130,7 @@ type Client struct {
129130
discoverNodesTimer *time.Timer
130131

131132
compressRequestBody bool
133+
compatibilityHeader bool
132134

133135
metrics *metrics
134136

@@ -194,6 +196,7 @@ func New(cfg Config) (*Client, error) {
194196
discoverNodesInterval: cfg.DiscoverNodesInterval,
195197

196198
compressRequestBody: cfg.CompressRequestBody,
199+
compatibilityHeader: cfg.CompatibilityHeader,
197200

198201
transport: cfg.Transport,
199202
logger: cfg.Logger,
@@ -240,7 +243,7 @@ func (c *Client) Perform(req *http.Request) (*http.Response, error) {
240243
)
241244

242245
// Compatibility Header
243-
if compatibilityHeader {
246+
if compatibilityHeader || c.compatibilityHeader {
244247
if req.Body != nil {
245248
req.Header.Set("Content-Type", "application/vnd.elasticsearch+json;compatible-with=7")
246249
}

0 commit comments

Comments
 (0)