Skip to content

Commit d20eb08

Browse files
authored
[typedclient] Add responses (#618)
* Add typedapi responses * Update integration test with responses & errors * Add highlights for typedapi changes * Add missing license headers * Fix missing pointers * Fix internal test for info on typedclient * Apply linter recommendations
1 parent bc507c4 commit d20eb08

File tree

2,729 files changed

+96745
-14383
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,729 files changed

+96745
-14383
lines changed

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# 8.7.0
2+
3+
## Typed API
4+
5+
* Inclusion of responses structures.
6+
7+
**Changes**
8+
9+
* `Do` method on endpoints now return a typed response, one per endpoint.
10+
* `Perform` method added on endpoints, returns `http.Response` as did `Do`.
11+
* Elasticsearch exceptions are now handled as `types.ElasticsearchError` with `.As` and `.Is` methods.
12+
* `.Raw` now takes a reader as input.
13+
* User defined values such as `_source` in `Hits` are now `json.RawMessage` to highlight they later deserializable nature.
14+
115
# 8.6.0
216

317
## API

elasticsearch_integration_test.go

+62-70
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ import (
2525
"context"
2626
"crypto/tls"
2727
"encoding/json"
28+
"errors"
2829
"fmt"
2930
"github.com/elastic/go-elasticsearch/v8/typedapi/core/search"
3031
"github.com/elastic/go-elasticsearch/v8/typedapi/indices/create"
3132
"github.com/elastic/go-elasticsearch/v8/typedapi/some"
3233
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
3334
"github.com/elastic/go-elasticsearch/v8/typedapi/types/enums/refresh"
35+
"github.com/elastic/go-elasticsearch/v8/typedapi/types/enums/result"
3436
"github.com/elastic/go-elasticsearch/v8/typedapi/types/enums/sortorder"
3537
"log"
3638
"net"
@@ -306,37 +308,24 @@ func TestTypedClient(t *testing.T) {
306308
if err != nil {
307309
t.Fatalf("error reading Info request: %s", err)
308310
}
309-
defer res.Body.Close()
310311

311-
var d map[string]interface{}
312-
err = json.NewDecoder(res.Body).Decode(&d)
313-
if err != nil {
314-
log.Fatalf("Error parsing the response: %s\n", err)
315-
}
316-
317-
if d["tagline"] != "You Know, for Search" {
318-
t.Errorf("invalid tagline, got: %s", d["tagline"])
312+
if res.Tagline != "You Know, for Search" {
313+
t.Errorf("invalid tagline, got: %s", res.Tagline)
319314
}
320315
})
321316

322317
t.Run("Index & Search", func(t *testing.T) {
323-
es, err := elasticsearch.NewTypedClient(elasticsearch.Config{})
324-
325-
u, _ := url.Parse("http://localhost:9200")
326-
tp, _ := elastictransport.New(
327-
elastictransport.Config{
328-
URLs: []*url.URL{u},
329-
Logger: &elastictransport.ColorLogger{os.Stdout, true, true},
330-
},
331-
)
332-
es.Transport = tp
318+
es, err := elasticsearch.NewTypedClient(elasticsearch.Config{
319+
Addresses: []string{"http://localhost:9200"},
320+
Logger: &elastictransport.ColorLogger{os.Stdout, true, true},
321+
})
333322
if err != nil {
334323
t.Fatalf("error creating the client: %s", err)
335324
}
336325

337326
// If the index doesn't exist we create it with a mapping.
338327
indexName := "test-index"
339-
if ok, err := es.Indices.Exists(indexName).IsSuccess(nil); !ok && err == nil {
328+
if exists, err := es.Indices.Exists(indexName).IsSuccess(context.Background()); !exists && err == nil {
340329
res, err := es.Indices.Create(indexName).
341330
Request(&create.Request{
342331
Mappings: &types.TypeMapping{
@@ -346,11 +335,15 @@ func TestTypedClient(t *testing.T) {
346335
},
347336
},
348337
}).
349-
Do(nil)
338+
Do(context.Background())
350339
if err != nil {
351340
t.Fatalf("error creating index test-index: %s", err)
352341
}
353-
defer res.Body.Close()
342+
343+
if !res.Acknowledged && res.Index != indexName {
344+
t.Fatalf("unexpected error during index creation, got : %#v", res)
345+
}
346+
354347
} else if err != nil {
355348
t.Error(err)
356349
}
@@ -363,11 +356,14 @@ func TestTypedClient(t *testing.T) {
363356
}
364357
}()
365358

366-
for _, document := range []struct {
359+
type Document struct {
367360
Id int `json:"id"`
368361
Name string `json:"name"`
369362
Price int `json:"price"`
370-
}{
363+
}
364+
365+
// Indexing synchronously with refresh.Waitfor, one document at a time
366+
for _, document := range []Document{
371367
{
372368
Id: 1,
373369
Name: "Foo",
@@ -384,21 +380,36 @@ func TestTypedClient(t *testing.T) {
384380
Price: 4,
385381
},
386382
} {
387-
indexResponse, err := es.Index(indexName).
383+
indexed, err := es.Index(indexName).
388384
Request(document).
389385
Id(strconv.Itoa(document.Id)).
390386
Refresh(refresh.Waitfor).
391387
Do(context.Background())
392388
if err != nil {
393389
t.Fatalf("error indexing document: %s", err)
394390
}
395-
defer indexResponse.Body.Close()
391+
if indexed.Result != result.Created {
392+
t.Fatalf("unexpected result during indexation of document: %v, response: %v", document, indexed)
393+
}
396394
}
397395

398-
if ok, err := es.Get(indexName, "1").IsSuccess(nil); !ok {
396+
// Check for document existence in index
397+
if ok, err := es.Get(indexName, "1").IsSuccess(context.Background()); !ok {
399398
t.Fatalf("could not retrieve document: %s", err)
400399
}
401400

401+
// Try to retrieve a faulty index name
402+
if ok, _ := es.Get("non-existent-index", "9999").IsSuccess(context.Background()); ok {
403+
t.Fatalf("index shouldn't exist")
404+
}
405+
406+
// Same faulty index name with error handling
407+
_, err = es.Get("non-existent-index", "9999").Do(context.Background())
408+
if !errors.As(err, &types.ElasticsearchError{}) && !errors.Is(err, &types.ElasticsearchError{Status: 404}) {
409+
t.Fatalf("expected ElasticsearchError, got: %v", err)
410+
}
411+
412+
// Simple search matching name
402413
res, err := es.Search().
403414
Index(indexName).
404415
Request(&search.Request{
@@ -412,48 +423,26 @@ func TestTypedClient(t *testing.T) {
412423
if err != nil {
413424
t.Fatalf("error runnning search query: %s", err)
414425
}
415-
defer res.Body.Close()
416426

417-
type SearchResult struct {
418-
Hits struct {
419-
Total struct {
420-
Value int
421-
Relation string
422-
} `json:"total"`
423-
Hits []struct {
424-
Index string `json:"_index"`
425-
Source struct {
426-
Id int
427-
Name string
428-
} `json:"_source"`
429-
} `json:"hits"`
430-
} `json:"hits"`
431-
}
432-
433-
sr := SearchResult{}
434-
435-
err = json.NewDecoder(res.Body).Decode(&sr)
436-
if err != nil {
437-
t.Fatal(err)
438-
}
439-
440-
if sr.Hits.Total.Value != 1 && sr.Hits.Hits[0].Source.Name != "Foo" {
427+
if res.Hits.Total.Value == 1 {
428+
doc := Document{}
429+
err = json.Unmarshal(res.Hits.Hits[0].Source_, &doc)
430+
if err != nil {
431+
t.Fatalf("cannot unmarshal document: %s", err)
432+
}
433+
if doc.Name != "Foo" {
434+
t.Fatalf("unexpected search result")
435+
}
436+
} else {
441437
t.Fatalf("unexpected search result")
442438
}
443439

444-
type PriceAggregation struct {
445-
Aggregations map[string]struct{ Value float64 } `json:"aggregations"`
446-
}
447-
448-
pa := PriceAggregation{}
449-
450-
size := 0
451-
452-
totalPricesAgg, err := es.Search().
440+
// Aggregate prices with a SumAggregation
441+
searchResponse, err := es.Search().
453442
Index(indexName).
454443
Request(
455444
&search.Request{
456-
Size: &size,
445+
Size: some.Int(0),
457446
Aggregations: map[string]types.Aggregations{
458447
"total_prices": {
459448
Sum: &types.SumAggregation{
@@ -466,15 +455,18 @@ func TestTypedClient(t *testing.T) {
466455
if err != nil {
467456
t.Fatal(err)
468457
}
469-
defer totalPricesAgg.Body.Close()
470-
471-
err = json.NewDecoder(totalPricesAgg.Body).Decode(&pa)
472-
if err != nil {
473-
t.Fatal(err)
474-
}
475458

476-
if pa.Aggregations["total_prices"].Value != 26. {
477-
t.Fatalf("error in aggregation, should be 26, got: %f", pa.Aggregations["total_prices"].Value)
459+
for name, agg := range searchResponse.Aggregations {
460+
if name == "total_prices" {
461+
switch aggregation := agg.(type) {
462+
case *types.SumAggregate:
463+
if aggregation.Value != 26. {
464+
t.Fatalf("error in aggregation, should be 26, got: %f", aggregation.Value)
465+
}
466+
default:
467+
fmt.Printf("unexpected aggregation: %#v\n", agg)
468+
}
469+
}
478470
}
479471
})
480472

elasticsearch_internal_test.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,13 @@ func TestNewTypedClient(t *testing.T) {
846846
Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
847847
StatusCode: http.StatusOK,
848848
Status: "OK",
849-
Body: ioutil.NopCloser(strings.NewReader("")),
849+
Body: ioutil.NopCloser(strings.NewReader(`{
850+
"version" : {
851+
"number" : "8.0.0-SNAPSHOT",
852+
"build_flavor" : "default"
853+
},
854+
"tagline" : "You Know, for Search"
855+
}`)),
850856
}, nil
851857
},
852858
},
@@ -859,7 +865,10 @@ func TestNewTypedClient(t *testing.T) {
859865
if err != nil {
860866
t.Fatalf("unexpected error: %s", err)
861867
}
862-
defer res.Body.Close()
868+
869+
if res.Tagline != "You Know, for Search" {
870+
t.Fatal("unexpected tagline")
871+
}
863872

864873
_, err = NewClient(Config{})
865874
if err != nil {

typedapi/api._.go

+1-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

typedapi/asyncsearch/delete/delete.go

+36-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)