func (c *Client) UpdateDocument(vaultID, docID string, document *models.EncryptedDocument, opts ...ReqOption) error {
	reqOpt := &ReqOpts{}
	for _, o := range opts {
		o(reqOpt)
	}
	jsonToSend, err := c.marshal(document)
	if err != nil {
		return fmt.Errorf("failed to marshal document: %w", err)
	}
	logger.Debugf("Sending request to update the following document: %s", jsonToSend)
	endpoint := c.edvServerURL + fmt.Sprintf("/%s/documents/%s", url.PathEscape(vaultID), url.PathEscape(docID))
	statusCode, _, respBytes, err := c.sendHTTPRequest(http.MethodPost, endpoint, jsonToSend, c.getHeaderFunc(reqOpt))
	if err != nil {
		return err
	}
	if statusCode == http.StatusOK || statusCode == http.StatusNoContent {
		return nil
	}
	return fmt.Errorf("the EDV server returned status code %d along with the following message: %s",
		statusCode, respBytes)
}
UpdateDocument sends the EDV server a request to update the specified document.
package client
import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"github.com/trustbloc/edge-core/pkg/log"
	"github.com/trustbloc/edv/pkg/restapi/models"
)
const failSendRequestForDocument = "failure while sending request to vault %s to retrieve document %s: %w"
var logger = log.New("edv-client")
type addHeaders func(req *http.Request) (*http.Header, error)
type marshalFunc func(interface{}) ([]byte, error)
type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}
type Client struct {
	edvServerURL string
	httpClient   HTTPClient
	marshal      marshalFunc
	headersFunc  addHeaders
}
type Option func(opts *Client)
func WithTLSConfig(tlsConfig *tls.Config) Option {
	return func(opts *Client) {
		if opts.httpClient == nil {
			logger.Errorf("WithTLSConfig: http client is nil")
			return
		}
		client, ok := opts.httpClient.(*http.Client)
		if !ok {
			logger.Errorf("WithTLSConfig: http client is not *http.Client")
			return
		}
		client.Transport = &http.Transport{TLSClientConfig: tlsConfig}
	}
}
func WithHTTPClient(client HTTPClient) Option {
	return func(opts *Client) {
		opts.httpClient = client
	}
}
func WithHeaders(addHeadersFunc addHeaders) Option {
	return func(opts *Client) {
		opts.headersFunc = addHeadersFunc
	}
}
type ReqOpts struct {
	addHeadersFunc addHeaders
}
type ReqOption func(opts *ReqOpts)
func WithRequestHeader(addHeadersFunc addHeaders) ReqOption {
	return func(opts *ReqOpts) {
		opts.addHeadersFunc = addHeadersFunc
	}
}
func New(edvServerURL string, opts ...Option) *Client {
	c := &Client{edvServerURL: edvServerURL, httpClient: &http.Client{}, marshal: json.Marshal}
	for _, opt := range opts {
		opt(c)
	}
	return c
}
func (c *Client) CreateDataVault(config *models.DataVaultConfiguration, opts ...ReqOption) (string, []byte, error) {
	reqOpt := &ReqOpts{}
	for _, o := range opts {
		o(reqOpt)
	}
	jsonToSend, err := c.marshal(config)
	if err != nil {
		return "", nil, fmt.Errorf("failed to marshal data vault configuration: %w", err)
	}
	logger.Debugf("Sending request to create a new data vault with the following data vault configuration: %s",
		jsonToSend)
	statusCode, httpHdr, respBytes, err := c.sendHTTPRequest(http.MethodPost, c.edvServerURL, jsonToSend,
		c.getHeaderFunc(reqOpt))
	if err != nil {
		return "", nil, err
	}
	if statusCode == http.StatusCreated {
		return httpHdr.Get("Location"), respBytes, nil
	}
	return "", nil, fmt.Errorf("the EDV server returned status code %d along with the following message: %s",
		statusCode, respBytes)
}
func (c *Client) CreateDocument(vaultID string, document *models.EncryptedDocument, opts ...ReqOption) (string, error) {
	reqOpt := &ReqOpts{}
	for _, o := range opts {
		o(reqOpt)
	}
	jsonToSend, err := c.marshal(document)
	if err != nil {
		return "", fmt.Errorf("failed to marshal document: %w", err)
	}
	logger.Debugf("Sending request to create the following document: %s", jsonToSend)
	statusCode, httpHdr, respBytes, err := c.sendHTTPRequest(http.MethodPost,
		c.edvServerURL+fmt.Sprintf("/%s/documents", url.PathEscape(vaultID)), jsonToSend, c.getHeaderFunc(reqOpt))
	if err != nil {
		return "", err
	}
	if statusCode == http.StatusCreated {
		return httpHdr.Get("Location"), nil
	}
	return "", fmt.Errorf("the EDV server returned status code %d along with the following message: %s",
		statusCode, respBytes)
}
func (c *Client) ReadDocument(vaultID, docID string, opts ...ReqOption) (*models.EncryptedDocument, error) {
	reqOpt := &ReqOpts{}
	for _, o := range opts {
		o(reqOpt)
	}
	endpoint := fmt.Sprintf("%s/%s/documents/%s", c.edvServerURL, url.PathEscape(vaultID), url.PathEscape(docID))
	statusCode, _, respBody, err := c.sendHTTPRequest(http.MethodGet, endpoint, nil, c.getHeaderFunc(reqOpt))
	if err != nil {
		return nil, fmt.Errorf(failSendRequestForDocument, vaultID, docID, err)
	}
	switch statusCode {
	case http.StatusOK:
		document := models.EncryptedDocument{}
		err = json.Unmarshal(respBody, &document)
		if err != nil {
			return nil, err
		}
		return &document, nil
	default:
		return nil, fmt.Errorf("the EDV server returned status code %d along with the following message: %s",
			statusCode, respBody)
	}
}
func (c *Client) QueryVault(vaultID, name, value string, opts ...ReqOption) ([]string, error) {
	reqOpt := &ReqOpts{}
	for _, o := range opts {
		o(reqOpt)
	}
	query := models.Query{
		ReturnFullDocuments: false,
		Name:                name,
		Value:               value,
	}
	jsonToSend, err := c.marshal(query)
	if err != nil {
		return nil, err
	}
	endpoint := fmt.Sprintf("%s/%s/query", c.edvServerURL, url.PathEscape(vaultID))
	statusCode, _, respBytes, err := c.sendHTTPRequest(http.MethodPost, endpoint, jsonToSend, c.getHeaderFunc(reqOpt))
	if err != nil {
		return nil, err
	}
	if statusCode == http.StatusOK {
		var docURLs []string
		err = json.Unmarshal(respBytes, &docURLs)
		if err != nil {
			return nil, err
		}
		return docURLs, nil
	}
	return nil, fmt.Errorf("the EDV server returned status code %d along with the following message: %s",
		statusCode, respBytes)
}
func (c *Client) QueryVaultForFullDocuments(vaultID, name, value string,
	opts ...ReqOption) ([]models.EncryptedDocument, error) {
	reqOpt := &ReqOpts{}
	for _, o := range opts {
		o(reqOpt)
	}
	query := models.Query{
		ReturnFullDocuments: true,
		Name:                name,
		Value:               value,
	}
	jsonToSend, err := c.marshal(query)
	if err != nil {
		return nil, err
	}
	endpoint := fmt.Sprintf("%s/%s/query", c.edvServerURL, url.PathEscape(vaultID))
	statusCode, _, respBytes, err := c.sendHTTPRequest(http.MethodPost, endpoint, jsonToSend, c.getHeaderFunc(reqOpt))
	if err != nil {
		return nil, err
	}
	if statusCode == http.StatusOK {
		var documents []models.EncryptedDocument
		err = json.Unmarshal(respBytes, &documents)
		if err != nil {
			return nil, err
		}
		return documents, nil
	}
	return nil, fmt.Errorf("the EDV server returned status code %d along with the following message: %s",
		statusCode, respBytes)
}