Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
hoanhan101 committed Apr 30, 2021
0 parents commit 809a57c
Show file tree
Hide file tree
Showing 11 changed files with 481 additions and 0 deletions.
38 changes: 38 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@


PKG_VERSION := 0.1.0
GIT_COMMIT ?= $(shell git rev-parse --short HEAD 2> /dev/null || true)
BUILD_DATE := $(shell date -u +%Y-%m-%dT%T 2> /dev/null)


.PHONY: clean
clean: ## Remove temporary files and build artifacts
go clean -v ./...
rm -rf bin
rm -f coverage.out

.PHONY: cover
cover: test-unit ## Run unit tests and open the coverage report
go tool cover -html=coverage.out

.PHONY: fmt
fmt: ## Run gofmt on all files
gofmt -s -w .

.PHONY: lint
lint: ## Lint project source files
docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.39.0 golangci-lint run

.PHONY: test-unit
test-unit: ## Run unit tests
go test -race -cover -run Unit -coverprofile=coverage.out -covermode=atomic ./...

.PHONY: version
version: ## Print the version
@echo "${PKG_VERSION}"

.PHONY: help
help: ## Print usage information
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort

.DEFAULT_GOAL := help
44 changes: 44 additions & 0 deletions examples/apiv7.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import (
"fmt"
"log"
"time"

"github.com/hoanhan101/veryfi-go/veryfi"
"github.com/hoanhan101/veryfi-go/veryfi/scheme"
)

func main() {
timeout, err := time.ParseDuration("10s")
if err != nil {
log.Fatal(err)
}

client, err := veryfi.NewClientV7(&veryfi.Options{
ClientID: "vrfZz1LVPAlaGpTb9Co29t0yerWpLsc3o0JXgxA",
Username: "hoanhan101",
APIKey: "5745c55a456b752ba0d78d673c7c095b",
HTTP: veryfi.HTTPOptions{
Timeout: timeout,
Retry: veryfi.RetryOptions{
Count: 1,
},
},
})
if err != nil {
log.Fatal(err)
}

resp, err := client.ProcessDocumentURL(scheme.DocumentURLOptions{
FileURL: "https://templates.invoicehome.com/invoice-template-us-neat-750px.png",
DocumentSharedOptions: scheme.DocumentSharedOptions{
Tags: []string{"electric", "repair", "ny"},
},
})
if err != nil {
log.Fatal(err)
}

fmt.Printf("%+v", resp)
}
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/hoanhan101/veryfi-go

go 1.16

require (
github.com/creasty/defaults v1.5.1
github.com/go-resty/resty/v2 v2.6.0
github.com/pkg/errors v0.9.1
golang.org/x/tools v0.1.0 // indirect
)
37 changes: 37 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
github.com/creasty/defaults v1.5.1 h1:j8WexcS3d/t4ZmllX4GEkl4wIB/trOr035ajcLHCISM=
github.com/creasty/defaults v1.5.1/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY=
github.com/go-resty/resty/v2 v2.6.0 h1:joIR5PNLM2EFqqESUjCMGXrWmXNHEU9CEiK813oKYS4=
github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
14 changes: 14 additions & 0 deletions veryfi/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package veryfi

import (
"github.com/hoanhan101/veryfi-go/veryfi/scheme"
)

// Client API for Veryfi.
type Client interface {
// Config returns the unified configuration info.
Config() *Options

// ProcessDocumentURL processes a file using a URL.
ProcessDocumentURL(scheme.DocumentURLOptions) (*scheme.Document, error)
}
116 changes: 116 additions & 0 deletions veryfi/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package veryfi

import (
"fmt"
"github.com/pkg/errors"

"github.com/go-resty/resty/v2"
"github.com/hoanhan101/veryfi-go/veryfi/scheme"
)

// httpClient implements a Veryfi API Client.
type httpClient struct {
// options is the global config options of the client.
options *Options

// client holds the resty.Client.
client *resty.Client

// apiVersion is the current API version of Veryfi that we are
// communicating with.
apiVersion string
}

// NewClientV7 returns a new instance of a client for v7 API.
func NewClientV7(opts *Options) (Client, error) {
c, err := createClient(opts)
if err != nil {
return nil, errors.Wrap(err, "failed to create a client")
}

return &httpClient{
options: opts,
client: c,
apiVersion: "v7",
}, nil
}

// createClient setups a resty client with configured options.
func createClient(opts *Options) (*resty.Client, error) {
err := setDefaults(opts)
if err != nil {
return nil, err
}

// Create a resty client with configured options.
client := resty.New()
client = client.
SetTimeout(opts.HTTP.Timeout).
SetRetryCount(int(opts.HTTP.Retry.Count)).
SetRetryWaitTime(opts.HTTP.Retry.WaitTime).
SetRetryMaxWaitTime(opts.HTTP.Retry.MaxWaitTime)

return client, nil
}

// Config returns the client configuration options.
func (c *httpClient) Config() *Options {
return c.options
}

// ProcessDocumentURL returns the processed document using URL.
func (c *httpClient) ProcessDocumentURL(opts scheme.DocumentURLOptions) (*scheme.Document, error) {
out := new(*scheme.Document)
if err := c.post(documentURI, opts, out); err != nil {
return nil, err
}

return *out, nil
}

// get performs a GET request against Veryfi API.
// func (c *httpClient) get(uri string, params map[string]string, okScheme interface{}) error {
// errScheme := new(scheme.Error)
// _, err := c.setBaseURL().R().SetQueryParams(params).SetResult(okScheme).SetError(errScheme).Get(uri)
// return check(err, errScheme)

// }

// post performs a POST request against Veryfi API.
func (c *httpClient) post(uri string, body interface{}, okScheme interface{}) error {
errScheme := new(scheme.Error)
_, err := c.setBaseURL().R().
SetBody(body).
SetHeaders(map[string]string{
"Content-Type": "application/json",
"Accept": "application/json",
"CLIENT-ID": c.options.ClientID,
"AUTHORIZATION": fmt.Sprintf("apikey %s:%s", c.options.Username, c.options.APIKey),
}).
SetResult(okScheme).
SetError(errScheme).
Post(uri)

return check(err, errScheme)
}

// setBaseURL returns a client that uses Veryfi's base URL.
func (c *httpClient) setBaseURL() *resty.Client {
return c.client.SetHostURL(buildURL(c.options.EnvironmentURL, "api", c.apiVersion))
}

// check validates returned response from Veryfi.
func check(err error, errResp *scheme.Error) error {
if err != nil {
return errors.Wrap(err, "failed to make a request to Veryfi")
}

if *errResp != (scheme.Error{}) {
return errors.Errorf(
"got a %v error response from Veryfi at %v, saying %v, with context: %v",
errResp.HTTPCode, errResp.Timestamp, errResp.Description, errResp.Context,
)
}

return nil
}
64 changes: 64 additions & 0 deletions veryfi/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package veryfi

import (
"time"

"github.com/creasty/defaults"
"github.com/pkg/errors"
)

// Options is the root config options
type Options struct {
// EnvironmentURL provided by Veryfi without trailing `/` or http scheme.
EnvironmentURL string `default:"api.veryfi.com"`

// ClientID provided by Veryfi.
ClientID string `default:"-"`

// Username provided by Veryfi.
Username string `default:"-"`

// APIKey provided by Veryfi.
APIKey string `default:"-"`

// HTTP specifies the options for http protocol, used by a http client.
HTTP HTTPOptions
}

// HTTPOptions is the config options for http protocol,
type HTTPOptions struct {
// Timeout specifies a time limit for a http request.
Timeout time.Duration `default:"3s"`

// Retry specifies the options for retry mechanism.
Retry RetryOptions
}

// RetryOptions is the config options for backoff retry mechanism. Its strategy
// is to increase retry intervals after each failed attempt, until some maximum
// value.
type RetryOptions struct {
// Count specifies the number of retry attempts. Zero value means no retry.
Count uint `default:"3"`

// WaitTime specifies the wait time before retrying request. It is
// increased after each attempt.
WaitTime time.Duration `default:"100ms"`

// MaxWaitTime specifies the maximum wait time, the cap, of all retry
// requests that are made.
MaxWaitTime time.Duration `default:"3s"`
}

// setDefaults setups default options.
func setDefaults(opts *Options) error {
if opts == nil {
return errors.New("options can not be nil")
}

if err := defaults.Set(opts); err != nil {
return errors.New("failed to set default configs")
}

return nil
}
Loading

0 comments on commit 809a57c

Please sign in to comment.