From e284861539cec6f3a0ad30d2295cd76d33c2d265 Mon Sep 17 00:00:00 2001 From: Alexander Zhuravlev Date: Tue, 14 May 2024 23:23:03 +0300 Subject: [PATCH] Raw encoder. --- README.md | 25 ++++++++++++++++ client/client.go | 2 +- client/client_test.go | 25 ++++++++++++++++ client/transport/encoder/rw.go | 54 ++++++++++++++++++++++++++++++++++ dadata_test.go | 25 ++++++++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 client/transport/encoder/rw.go diff --git a/README.md b/README.md index c39f695..4be0ef7 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,31 @@ httpClient := &http.Client{} api := NewSuggestApi(WithHttpClient(httpClient)) ``` +### Low level client usage + +Pass and consume raw bytes/strings: + +```go + endpointUrl, err := url.Parse("https://suggestions.dadata.ru/suggestions/api/4_1/rs/") + if err != nil { + return + } + + cli := client.NewClient(endpointUrl, + client.WithEncoderFactory(encoder.RawEncoderFactory()), + client.WithDecoderFactory(encoder.RawDecoderFactory()), + ) + + request := bytes.NewBufferString("{ \"query\": \"москва хабар\" }") + response := &bytes.Buffer{} + + err = cli.Post(context.Background(), "suggest/address", request, response) + if err != nil { + return + } + + fmt.Print(response.String()) // Output: `{"suggestions":[{"value":"г Москва, ул Хабаровская",...` +``` ## Licence MIT see [LICENSE](LICENSE) diff --git a/client/client.go b/client/client.go index 26d34c0..4765163 100644 --- a/client/client.go +++ b/client/client.go @@ -94,7 +94,7 @@ func (c *Client) doRequest(ctx context.Context, method string, url *url.URL, bod ) } - if err = c.options.decoderFactory(response.Body)(&result); err != nil { + if err = c.options.decoderFactory(response.Body)(result); err != nil { return fmt.Errorf("doRequest: response body decode err: %w", err) } diff --git a/client/client_test.go b/client/client_test.go index 22595c2..b0757c9 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1,6 +1,7 @@ package client import ( + "bytes" "context" "encoding/json" "fmt" @@ -9,6 +10,7 @@ import ( "github.com/ekomobile/dadata/v2/api/suggest" "github.com/ekomobile/dadata/v2/client/transport" + "github.com/ekomobile/dadata/v2/client/transport/encoder" ) func ExampleNewClient() { @@ -108,3 +110,26 @@ func ExampleWithEncoderFactory() { fmt.Printf("%s", s.Value) } } + +func ExampleClient_low_level() { + var err error + endpointUrl, err := url.Parse("https://suggestions.dadata.ru/suggestions/api/4_1/rs/") + if err != nil { + return + } + + cli := NewClient(endpointUrl, + WithEncoderFactory(encoder.RawEncoderFactory()), + WithDecoderFactory(encoder.RawDecoderFactory()), + ) + + request := bytes.NewBufferString("{ \"query\": \"москва хабар\" }") + response := &bytes.Buffer{} + + err = cli.Post(context.Background(), "suggest/address", request, response) + if err != nil { + return + } + + fmt.Print(response.String()) +} diff --git a/client/transport/encoder/rw.go b/client/transport/encoder/rw.go new file mode 100644 index 0000000..4fe9669 --- /dev/null +++ b/client/transport/encoder/rw.go @@ -0,0 +1,54 @@ +package encoder + +import ( + "fmt" + "io" + + "github.com/ekomobile/dadata/v2/client/transport" +) + +// RawEncoderFactory is a factory for noop-encoder that just writes to transport io.Writer. +func RawEncoderFactory() transport.EncoderFactory { + return func(w io.Writer) transport.Encoder { + return func(v interface{}) (err error) { + switch value := v.(type) { + case *string: + _, err = w.Write([]byte(*value)) + case string: + _, err = w.Write([]byte(value)) + case *[]byte: + _, err = w.Write(*value) + case []byte: + _, err = w.Write(value) + case io.Reader: + _, err = io.Copy(w, value) + case io.WriterTo: + _, err = value.WriteTo(w) + default: + err = fmt.Errorf("can not encode from value: %#v", v) + } + return err + } + } +} + +// RawDecoderFactory is a factory for noop-decoder that just reads from transport io.Reader. +func RawDecoderFactory() transport.DecoderFactory { + return func(r io.Reader) transport.Decoder { + return func(v interface{}) (err error) { + switch value := v.(type) { + case *[]byte: + _, err = r.Read(*value) + case []byte: + _, err = r.Read(value) + case io.Writer: + _, err = io.Copy(value, r) + case io.ReaderFrom: + _, err = value.ReadFrom(r) + default: + err = fmt.Errorf("can not decode into value: %#v", v) + } + return err + } + } +} diff --git a/dadata_test.go b/dadata_test.go index 5c08a94..e76d937 100644 --- a/dadata_test.go +++ b/dadata_test.go @@ -3,11 +3,15 @@ package dadata import ( + "bytes" "context" "fmt" + "net/url" "os" "testing" + "github.com/ekomobile/dadata/v2/client" + "github.com/ekomobile/dadata/v2/client/transport/encoder" "github.com/stretchr/testify/suite" "github.com/ekomobile/dadata/v2/api/suggest" @@ -53,6 +57,27 @@ func (s *ApiSuggestIntegrationTest) TestAddress() { s.NotEmpty(res) } +func (s *ApiSuggestIntegrationTest) TestAddress_low_level() { + var err error + endpointUrl, err := url.Parse(EndpointURLSuggest) + if err != nil { + return + } + + cli := client.NewClient(endpointUrl, + client.WithEncoderFactory(encoder.RawEncoderFactory()), + client.WithDecoderFactory(encoder.RawDecoderFactory()), + ) + + request := bytes.NewBufferString("{ \"query\": \"москва хабар\" }") + response := &bytes.Buffer{} + + err = cli.Post(context.Background(), "suggest/address", request, response) + + s.NoError(err) + s.NotEmpty(response.String()) +} + func (s *ApiSuggestIntegrationTest) TestAddressWithLanguageParamRU() { api := NewSuggestApi()