Skip to content

Commit 82fc17d

Browse files
committed
Fix JSONReader integration with client
This patch updates the esapi.newRequest() function to handle body passed as esutil.JSONReader properly. It makes the esutil.JSONReader exported, and renames the constructor function to esutil.NewJSONReader(). It also adds proper integration tests for esutil.JSONReader.
1 parent 04312bb commit 82fc17d

6 files changed

+146
-14
lines changed

_examples/encoding/jsonreader.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/elastic/go-elasticsearch/v8"
7+
"github.com/elastic/go-elasticsearch/v8/esapi"
8+
"github.com/elastic/go-elasticsearch/v8/esutil"
9+
)
10+
11+
func init() {
12+
log.SetFlags(0)
13+
}
14+
15+
func main() {
16+
var (
17+
res *esapi.Response
18+
err error
19+
)
20+
21+
es, err := elasticsearch.NewDefaultClient()
22+
if err != nil {
23+
log.Fatalf("Error creating the client: %s", err)
24+
}
25+
26+
doc := struct {
27+
Title string `json:"title"`
28+
}{Title: "Test"}
29+
30+
res, err = es.Index("test", esutil.NewJSONReader(&doc), es.Index.WithRefresh("true"))
31+
if err != nil {
32+
log.Fatalf("Error getting response: %s", err)
33+
}
34+
35+
log.Println(res)
36+
37+
query := map[string]interface{}{
38+
"query": map[string]interface{}{
39+
"match": map[string]interface{}{
40+
"title": "test",
41+
},
42+
},
43+
}
44+
45+
res, err = es.Search(
46+
es.Search.WithIndex("test"),
47+
es.Search.WithBody(esutil.NewJSONReader(&query)),
48+
es.Search.WithPretty(),
49+
)
50+
if err != nil {
51+
log.Fatalf("Error getting response: %s", err)
52+
}
53+
54+
log.Println(res)
55+
}

esapi/esapi.request.go

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ func newRequest(method, path string, body io.Reader) (*http.Request, error) {
4747
case *strings.Reader:
4848
r.Body = ioutil.NopCloser(body)
4949
r.ContentLength = int64(b.Len())
50+
default:
51+
r.Body = ioutil.NopCloser(body)
5052
}
5153
}
5254

esutil/json_reader.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import (
66
"io"
77
)
88

9-
// JSONReader is an utility function which encodes v into JSON and returns it as a reader.
9+
// NewJSONReader encodes v into JSON and returns it as an io.Reader.
1010
//
11-
func JSONReader(v interface{}) io.Reader {
12-
return &jsonReader{val: v, buf: nil}
11+
func NewJSONReader(v interface{}) io.Reader {
12+
return &JSONReader{val: v, buf: nil}
1313
}
1414

1515
// JSONEncoder defines the interface for custom JSON encoders.
@@ -18,15 +18,20 @@ type JSONEncoder interface {
1818
EncodeJSON(io.Writer) error
1919
}
2020

21-
type jsonReader struct {
21+
// JSONReader represents a reader which takes an interface value,
22+
// encodes it into JSON, and wraps it in an io.Reader.
23+
//
24+
type JSONReader struct {
2225
val interface{}
2326
buf interface {
2427
io.ReadWriter
2528
io.WriterTo
2629
}
2730
}
2831

29-
func (r *jsonReader) Read(p []byte) (int, error) {
32+
// Read implements the io.Reader interface.
33+
//
34+
func (r *JSONReader) Read(p []byte) (int, error) {
3035
if r.buf == nil {
3136
r.buf = new(bytes.Buffer)
3237
if err := r.encode(r.buf); err != nil {
@@ -37,13 +42,15 @@ func (r *jsonReader) Read(p []byte) (int, error) {
3742
return r.buf.Read(p)
3843
}
3944

40-
func (r *jsonReader) WriteTo(w io.Writer) (int64, error) {
45+
// WriteTo implements the io.WriterTo interface.
46+
//
47+
func (r *JSONReader) WriteTo(w io.Writer) (int64, error) {
4148
cw := countingWriter{Writer: w}
4249
err := r.encode(&cw)
4350
return int64(cw.n), err
4451
}
4552

46-
func (r *jsonReader) encode(w io.Writer) error {
53+
func (r *JSONReader) encode(w io.Writer) error {
4754
var err error
4855

4956
if e, ok := r.val.(JSONEncoder); ok {

esutil/json_reader_benchmark_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func BenchmarkJSONReader(b *testing.B) {
5353
b.ResetTimer()
5454

5555
for i := 0; i < b.N; i++ {
56-
out, _ := ioutil.ReadAll(esutil.JSONReader(map[string]string{"foo": "bar"}))
56+
out, _ := ioutil.ReadAll(esutil.NewJSONReader(map[string]string{"foo": "bar"}))
5757
if string(out) != `{"foo":"bar"}`+"\n" {
5858
b.Fatalf("Unexpected output: %q", out)
5959
}
@@ -65,7 +65,7 @@ func BenchmarkJSONReader(b *testing.B) {
6565

6666
var buf bytes.Buffer
6767
for i := 0; i < b.N; i++ {
68-
io.Copy(&buf, esutil.JSONReader(map[string]string{"foo": "bar"}))
68+
io.Copy(&buf, esutil.NewJSONReader(map[string]string{"foo": "bar"}))
6969
if buf.String() != `{"foo":"bar"}`+"\n" {
7070
b.Fatalf("Unexpected output: %q", buf.String())
7171
}
@@ -77,7 +77,7 @@ func BenchmarkJSONReader(b *testing.B) {
7777
b.ResetTimer()
7878

7979
for i := 0; i < b.N; i++ {
80-
out, _ := ioutil.ReadAll(esutil.JSONReader(Foo{Bar: "baz"}))
80+
out, _ := ioutil.ReadAll(esutil.NewJSONReader(Foo{Bar: "baz"}))
8181
if string(out) != `{"bar":"BAZ"}`+"\n" {
8282
b.Fatalf("Unexpected output: %q", out)
8383
}
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// +build integration
2+
3+
package esutil_test
4+
5+
import (
6+
"strings"
7+
"testing"
8+
9+
"github.com/elastic/go-elasticsearch/v8"
10+
"github.com/elastic/go-elasticsearch/v8/esapi"
11+
"github.com/elastic/go-elasticsearch/v8/esutil"
12+
)
13+
14+
func TestJSONReaderIntegration(t *testing.T) {
15+
t.Run("Index and search", func(t *testing.T) {
16+
var (
17+
res *esapi.Response
18+
err error
19+
)
20+
21+
es, err := elasticsearch.NewDefaultClient()
22+
if err != nil {
23+
t.Fatalf("Error creating the client: %s\n", err)
24+
}
25+
26+
es.Indices.Delete([]string{"test"})
27+
28+
doc := struct {
29+
Title string `json:"title"`
30+
}{Title: "Foo Bar"}
31+
32+
res, err = es.Index("test", esutil.NewJSONReader(&doc), es.Index.WithRefresh("true"))
33+
if err != nil {
34+
t.Fatalf("Error getting response: %s", err)
35+
}
36+
defer res.Body.Close()
37+
38+
if res.IsError() {
39+
t.Fatalf("Error response: %s", res.String())
40+
}
41+
42+
query := map[string]interface{}{
43+
"query": map[string]interface{}{
44+
"match": map[string]interface{}{
45+
"title": "foo",
46+
},
47+
},
48+
}
49+
50+
res, err = es.Search(
51+
es.Search.WithIndex("test"),
52+
es.Search.WithBody(esutil.NewJSONReader(&query)),
53+
es.Search.WithPretty(),
54+
)
55+
if err != nil {
56+
t.Fatalf("Error getting response: %s", err)
57+
}
58+
defer res.Body.Close()
59+
60+
if res.IsError() {
61+
t.Errorf("Error response: %s", res)
62+
}
63+
64+
if !strings.Contains(res.String(), "Foo Bar") {
65+
t.Errorf("Unexpected response: %s", res)
66+
}
67+
})
68+
}

esutil/json_reader_internal_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@ func (f Foo) EncodeJSON(w io.Writer) error {
3131

3232
func TestJSONReader(t *testing.T) {
3333
t.Run("Default", func(t *testing.T) {
34-
out, _ := ioutil.ReadAll(JSONReader(map[string]string{"foo": "bar"}))
34+
out, _ := ioutil.ReadAll(NewJSONReader(map[string]string{"foo": "bar"}))
3535
if string(out) != `{"foo":"bar"}`+"\n" {
3636
t.Fatalf("Unexpected output: %s", out)
3737
}
3838
})
3939

4040
t.Run("Custom", func(t *testing.T) {
41-
out, _ := ioutil.ReadAll(JSONReader(Foo{Bar: "baz"}))
41+
out, _ := ioutil.ReadAll(NewJSONReader(Foo{Bar: "baz"}))
4242
if string(out) != `{"bar":"BAZ"}`+"\n" {
4343
t.Fatalf("Unexpected output: %s", out)
4444
}
4545
})
4646

4747
t.Run("WriteTo", func(t *testing.T) {
4848
b := bytes.NewBuffer([]byte{})
49-
r := jsonReader{val: map[string]string{"foo": "bar"}}
49+
r := JSONReader{val: map[string]string{"foo": "bar"}}
5050
r.WriteTo(b)
5151
if b.String() != `{"foo":"bar"}`+"\n" {
5252
t.Fatalf("Unexpected output: %s", b.String())
@@ -55,7 +55,7 @@ func TestJSONReader(t *testing.T) {
5555

5656
t.Run("Read error", func(t *testing.T) {
5757
b := []byte{}
58-
r := jsonReader{val: map[string]string{"foo": "bar"}, buf: errReader{}}
58+
r := JSONReader{val: map[string]string{"foo": "bar"}, buf: errReader{}}
5959
_, err := r.Read(b)
6060
if err == nil {
6161
t.Fatalf("Expected error, got: %#v", err)

0 commit comments

Comments
 (0)