Skip to content

Commit 1b3281f

Browse files
committed
url and upload endpoints compatibility
1 parent cf62245 commit 1b3281f

File tree

3 files changed

+290
-1
lines changed

3 files changed

+290
-1
lines changed

README.md

+53-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,53 @@
1-
# kraken-go
1+
# kraken-go
2+
### Installation
3+
`$go get github.com/kraken-io/kraken-go`
4+
Then add to your project:
5+
`import "github.com/kraken-io/kraken-go"`
6+
### Usage - Image URL
7+
kr, err := kraken.New("api_key", "api_secret")
8+
if err != nil {
9+
log.Fatal(err)
10+
}
11+
params := map[string]interface{}{
12+
"wait": true,
13+
"url": "http://image-url.com/file.jpg",
14+
"resize": map[string]interface{}{
15+
"width": 100,
16+
"height": 75,
17+
"strategy": "crop",
18+
},
19+
}
20+
21+
data, err := kr.URL(params)
22+
if err != nil {
23+
log.Fatal(err)
24+
}
25+
if data["success"] != true {
26+
log.Println("Failed, error message ", data["message"])
27+
} else {
28+
log.Println("Success, Optimized image URL: ", data["kraked_url"])
29+
}
30+
### Usage - Image upload
31+
kr, err := kraken.New("api_key", "api_secret")
32+
if err != nil {
33+
log.Fatal(err)
34+
}
35+
params := map[string]interface{}{
36+
"wait": true,
37+
"resize": map[string]interface{}{
38+
"width": 100,
39+
"height": 75,
40+
"strategy": "crop",
41+
},
42+
}
43+
44+
imgPath := "/path_to_file.jpg"
45+
data, err := kr.Upload(params, imgPath)
46+
if err != nil {
47+
t.Fatal("err ", err)
48+
}
49+
if data["success"] != true {
50+
log.Println("Failed, error message ", data["message"])
51+
} else {
52+
log.Println("Success, Optimized image URL: ", data["kraked_url"])
53+
}

kraken.go

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//Package kraken is the official client's implementation for Kraken.io API
2+
//https://github.com/kraken-io/kraken-go
3+
package kraken
4+
5+
import (
6+
"bytes"
7+
"encoding/json"
8+
"fmt"
9+
"io"
10+
"io/ioutil"
11+
"mime/multipart"
12+
"net/http"
13+
"os"
14+
"path/filepath"
15+
)
16+
17+
var (
18+
//ErrNoCred indicates that api_key or api_secret were not specified
19+
ErrNoCred = fmt.Errorf("key and secret should be specified")
20+
)
21+
22+
//ResponseError contains error encountered while processing HTTP response
23+
//with response itself
24+
type ResponseError struct {
25+
s string
26+
Resp *http.Response
27+
}
28+
29+
func (err *ResponseError) Error() string { return err.s }
30+
31+
//Kraken holds api_key, api_secret, and HttpClient
32+
type Kraken struct {
33+
auth map[string]string
34+
//If not specified default http.Client{} is used
35+
HTTPClient *http.Client
36+
}
37+
38+
//New creates new instance of Kraken. key and secret shouldn't be empty,otherwise ErrNoCred will be returned
39+
func New(key, secret string) (*Kraken, error) {
40+
if key == "" || secret == "" {
41+
return nil, ErrNoCred
42+
}
43+
return &Kraken{
44+
auth: map[string]string{
45+
"api_key": key,
46+
"api_secret": secret,
47+
},
48+
HTTPClient: http.DefaultClient,
49+
}, nil
50+
}
51+
52+
//URL makes request to the https://api.kraken.io/v1/upload endpoint
53+
func (kr *Kraken) URL(params map[string]interface{}) (map[string]interface{}, error) {
54+
dataReq, err := kr.marshalParams(params)
55+
if err != nil {
56+
return nil, err
57+
}
58+
req, err := http.NewRequest("POST", "https://api.kraken.io/v1/url", bytes.NewBuffer(dataReq))
59+
if err != nil {
60+
return nil, err
61+
}
62+
req.Header.Set("Content-Type", "application/json")
63+
req.Header.Set("Accept", "application/json")
64+
65+
return kr.doReq(req)
66+
}
67+
68+
//Upload makes multipart request to the https://api.kraken.io/v1/url endpoint
69+
func (kr *Kraken) Upload(params map[string]interface{}, path string) (map[string]interface{}, error) {
70+
file, err := os.Open(path)
71+
if err != nil {
72+
return nil, err
73+
}
74+
defer file.Close()
75+
76+
pipeReader, pipeWriter := io.Pipe()
77+
writer := multipart.NewWriter(pipeWriter)
78+
79+
req, err := http.NewRequest("POST", "https://api.kraken.io/v1/upload", pipeReader)
80+
if err != nil {
81+
return nil, err
82+
}
83+
req.Header.Add("Content-Type", writer.FormDataContentType())
84+
cancelCh := make(chan struct{})
85+
req.Cancel = cancelCh
86+
87+
errCh := make(chan error, 1)
88+
go func() {
89+
defer pipeWriter.Close()
90+
data, err := kr.marshalParams(params)
91+
if err != nil {
92+
errCh <- err
93+
close(cancelCh)
94+
return
95+
}
96+
dataPart, err := writer.CreateFormField("data")
97+
if err != nil {
98+
errCh <- err
99+
close(cancelCh)
100+
return
101+
}
102+
_, err = dataPart.Write(data)
103+
if err != nil {
104+
errCh <- err
105+
close(cancelCh)
106+
return
107+
}
108+
uploadPart, err := writer.CreateFormFile("upload", filepath.Base(path))
109+
if err != nil {
110+
errCh <- err
111+
close(cancelCh)
112+
return
113+
}
114+
_, err = io.Copy(uploadPart, file)
115+
if err != nil {
116+
errCh <- err
117+
close(cancelCh)
118+
return
119+
}
120+
err = writer.Close()
121+
if err != nil {
122+
errCh <- err
123+
close(cancelCh)
124+
}
125+
}()
126+
127+
dataResp, err := kr.doReq(req)
128+
if err != nil {
129+
select {
130+
case err := <-errCh:
131+
return nil, err
132+
default:
133+
return nil, err
134+
}
135+
}
136+
return dataResp, nil
137+
}
138+
func (kr *Kraken) marshalParams(params map[string]interface{}) ([]byte, error) {
139+
params["auth"] = kr.auth
140+
return json.Marshal(params)
141+
}
142+
func (kr *Kraken) doReq(req *http.Request) (map[string]interface{}, error) {
143+
resp, err := kr.HTTPClient.Do(req)
144+
if err != nil {
145+
return nil, err
146+
}
147+
defer resp.Body.Close()
148+
149+
body, err := ioutil.ReadAll(resp.Body)
150+
if err != nil {
151+
return nil, &ResponseError{err.Error(), resp}
152+
}
153+
dataResp := make(map[string]interface{})
154+
err = json.Unmarshal(body, &dataResp)
155+
if err != nil {
156+
resp.Body = ioutil.NopCloser(bytes.NewBuffer(body))
157+
return nil, &ResponseError{err.Error(), resp}
158+
}
159+
return dataResp, nil
160+
}

kraken_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package kraken_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/kraken-io/kraken-go"
7+
)
8+
9+
func TestErrors(t *testing.T) {
10+
kr, err := kraken.New("api_key", "")
11+
if err != kraken.ErrNoCred {
12+
t.Fatal("expected ErrNoAuth error")
13+
}
14+
15+
kr, err = kraken.New("api_key", "api_secret")
16+
if err != nil {
17+
t.Fatal(err)
18+
}
19+
20+
imgPath := "./notexist.jpeg"
21+
params := map[string]interface{}{}
22+
_, err = kr.Upload(params, imgPath)
23+
if err == nil {
24+
t.Fatal("Should throw error")
25+
}
26+
}
27+
28+
func TestURL(t *testing.T) {
29+
kr, err := kraken.New("api_key", "api_secret")
30+
if err != nil {
31+
t.Fatal(err)
32+
}
33+
params := map[string]interface{}{
34+
"wait": true,
35+
"url": "https://www.planwallpaper.com/static/images/canberra_hero_image_JiMVvYU.jpg",
36+
"resize": map[string]interface{}{
37+
"width": 100,
38+
"height": 75,
39+
"strategy": "crop",
40+
},
41+
}
42+
data, err := kr.URL(params)
43+
if err != nil {
44+
t.Fatal(err)
45+
}
46+
if data["success"] == true {
47+
t.Fatal("success's value should be false")
48+
}
49+
if data["message"] != "Unnknown API Key. Please check your API key and try again." {
50+
t.Fatal("Unexpected message ", data["message"])
51+
}
52+
}
53+
func TestUpload(t *testing.T) {
54+
kr, err := kraken.New("api_key", "api_secret")
55+
if err != nil {
56+
t.Fatal(err)
57+
}
58+
params := map[string]interface{}{
59+
"wait": true,
60+
"resize": map[string]interface{}{
61+
"width": 100,
62+
"height": 75,
63+
"strategy": "crop",
64+
},
65+
}
66+
imgPath := "./img.jpeg"
67+
data, err := kr.Upload(params, imgPath)
68+
if err != nil {
69+
t.Fatal(err)
70+
}
71+
if data["success"] == true {
72+
t.Fatal("success's value should be false")
73+
}
74+
if data["message"] != "Unnknown API Key. Please check your API key and try again." {
75+
t.Fatal("Unexpected message ", data["message"])
76+
}
77+
}

0 commit comments

Comments
 (0)