164 lines
3.9 KiB
Go
164 lines
3.9 KiB
Go
|
// Golang client library for DaData.ru (https://dadata.ru/).
|
||
|
|
||
|
// Package dadata implemented cleaning (https://dadata.ru/api/clean/) and suggesting (https://dadata.ru/api/suggest/)
|
||
|
package dadata
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
defaultBaseURL = "https://dadata.ru/api/v2/"
|
||
|
defaultBaseSuggestURL = "https://suggestions.dadata.ru/suggestions/api/4_1/rs/"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
Client struct {
|
||
|
options clientOptions
|
||
|
}
|
||
|
|
||
|
CredentialProvider interface {
|
||
|
ApiKey() string
|
||
|
SecretKey() string
|
||
|
}
|
||
|
|
||
|
Credentials struct {
|
||
|
ApiKeyValue string
|
||
|
SecretKeyValue string
|
||
|
}
|
||
|
|
||
|
EnvironmentCredentials struct {
|
||
|
ApiKeyName string
|
||
|
SecretKeyName string
|
||
|
}
|
||
|
|
||
|
clientOptions struct {
|
||
|
httpClient *http.Client
|
||
|
credentialProvider CredentialProvider
|
||
|
baseURL string
|
||
|
baseSuggestURL string
|
||
|
}
|
||
|
|
||
|
ClientOption func(opts *clientOptions)
|
||
|
)
|
||
|
|
||
|
// NewClient Create new client of DaData.
|
||
|
// Api and secret keys see on profile page (https://dadata.ru/profile/).
|
||
|
// By default client uses `DADATA_API_KEY` and `DADATA_SECRET_KEY` environment variables.
|
||
|
func NewClient(opts ...ClientOption) *Client {
|
||
|
options := clientOptions{
|
||
|
httpClient: http.DefaultClient,
|
||
|
credentialProvider: &EnvironmentCredentials{
|
||
|
ApiKeyName: "DADATA_API_KEY",
|
||
|
SecretKeyName: "DADATA_SECRET_KEY",
|
||
|
},
|
||
|
baseURL: defaultBaseURL,
|
||
|
baseSuggestURL: defaultBaseSuggestURL,
|
||
|
}
|
||
|
|
||
|
applyOptions(&options, opts...)
|
||
|
|
||
|
return &Client{
|
||
|
options: options,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *Client) sendRequestToURL(ctx context.Context, method, url string, source interface{}, result interface{}) error {
|
||
|
if err := ctx.Err(); err != nil {
|
||
|
return fmt.Errorf("sendRequestToURL: ctx.Err return err=%v", err)
|
||
|
}
|
||
|
|
||
|
buffer := &bytes.Buffer{}
|
||
|
|
||
|
if err := json.NewEncoder(buffer).Encode(source); err != nil {
|
||
|
return fmt.Errorf("sendRequestToURL: json.Encode return err = %v", err)
|
||
|
}
|
||
|
|
||
|
request, err := http.NewRequest(method, url, buffer)
|
||
|
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("sendRequestToURL: http.NewRequest return err = %v", err)
|
||
|
}
|
||
|
|
||
|
request = request.WithContext(ctx)
|
||
|
|
||
|
request.Header.Add("Authorization", fmt.Sprintf("Token %s", c.options.credentialProvider.ApiKey()))
|
||
|
request.Header.Add("X-Secret", c.options.credentialProvider.SecretKey())
|
||
|
request.Header.Add("Content-Type", "application/json")
|
||
|
request.Header.Add("Accept", "application/json")
|
||
|
|
||
|
response, err := c.options.httpClient.Do(request)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("sendRequestToURL: httpClient.Do return err = %v", err)
|
||
|
}
|
||
|
|
||
|
defer response.Body.Close()
|
||
|
|
||
|
if http.StatusOK != response.StatusCode {
|
||
|
return fmt.Errorf("sendRequestToURL: Request error %v", response.Status)
|
||
|
}
|
||
|
|
||
|
if err = json.NewDecoder(response.Body).Decode(&result); err != nil {
|
||
|
return fmt.Errorf("sendRequestToURL: json.Decode return err = %v", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// sendRequest
|
||
|
func (c *Client) sendRequest(ctx context.Context, lastURLPart string, source interface{}, result interface{}) error {
|
||
|
return c.sendRequestToURL(ctx, "POST", c.options.baseURL+lastURLPart, source, result)
|
||
|
}
|
||
|
|
||
|
func WithHttpClient(c *http.Client) ClientOption {
|
||
|
return func(opts *clientOptions) {
|
||
|
opts.httpClient = c
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WithCredentialProvider sets credential provider.
|
||
|
func WithCredentialProvider(c CredentialProvider) ClientOption {
|
||
|
return func(opts *clientOptions) {
|
||
|
opts.credentialProvider = c
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithBaseURL(url string) ClientOption {
|
||
|
return func(opts *clientOptions) {
|
||
|
opts.baseURL = url
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithBaseSuggestURL(url string) ClientOption {
|
||
|
return func(opts *clientOptions) {
|
||
|
opts.baseSuggestURL = url
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func applyOptions(options *clientOptions, opts ...ClientOption) {
|
||
|
for _, o := range opts {
|
||
|
o(options)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *Credentials) ApiKey() string {
|
||
|
return c.ApiKeyValue
|
||
|
}
|
||
|
|
||
|
func (c *Credentials) SecretKey() string {
|
||
|
return c.SecretKeyValue
|
||
|
}
|
||
|
|
||
|
func (c *EnvironmentCredentials) ApiKey() string {
|
||
|
return os.Getenv(c.ApiKeyName)
|
||
|
}
|
||
|
|
||
|
func (c *EnvironmentCredentials) SecretKey() string {
|
||
|
return os.Getenv(c.SecretKeyName)
|
||
|
}
|