Skip to content

Instantly share code, notes, and snippets.

@vodolaz095
Created January 18, 2016 13:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vodolaz095/5443ed253caeaa84f1ac to your computer and use it in GitHub Desktop.
Save vodolaz095/5443ed253caeaa84f1ac to your computer and use it in GitHub Desktop.
Small Go Powered parser to query Yahoo api for money xchange rates and store data in redis database
package main
/*
Test task: Small Go powered parser to query Yahoo api
for money xchange rates and store data
in local redis database.
Time taken ~1 hour
*/
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
"gopkg.in/redis.v3"
)
//API url
const exchangeRateURL = "https://query.yahooapis.com/v1/public/yql?q=select+*+from+yahoo.finance.xchange+where+pair+=+%22USDRUB,EURRUB%22&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback="
//Rate stores information about exchange rate for current object
type Rate struct {
ID string `json:"id"`
Name string `json:"Name"`
Rate string `json:"Rate"`
Ask string `json:"Ask"`
Bid string `json:"Bid"`
}
type responseQuery struct {
Count int `json:"count"`
Created time.Time `json:"created"`
ResultsRate responseResults `json:"results"`
}
type responseResults struct {
Rate []Rate `json:"rate"`
}
type response struct {
Query responseQuery `json:"query"`
}
//GetRates performs getting information from 3rd party api
func GetRates() ([]Rate, error) {
rP := response{}
client := &http.Client{}
req, err := http.NewRequest("GET", exchangeRateURL, nil)
if err != nil {
return nil, err
}
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode == 200 {
raw, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal(raw, &rP)
if err != nil {
return nil, err
}
return rP.Query.ResultsRate.Rate, err
}
return nil, fmt.Errorf("Wrong status code - %d", res.StatusCode)
}
//RedisStorage is a interface to redis database
type RedisStorage struct {
Client *redis.Client
}
//InitRedisStorage is a constructor for redis database client, loads config from OS environment values of `REDIS_HOST`,`REDIS_PORT`,`REDIS_AUTHPASS`
func InitRedisStorage() (RedisStorage, error) {
host := os.Getenv("REDIS_HOST")
if host == "" {
host = "localhost"
}
port := os.Getenv("REDIS_PORT")
if port == "" {
port = "6379"
}
auth := os.Getenv("REDIS_AUTHPASS")
client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%s", host, port),
Password: auth,
DB: 0, // use default DB
})
return RedisStorage{Client: client}, nil
}
//StoreRate saves Rate's values into database
func (rs *RedisStorage) StoreRate(v Rate, now time.Time) error {
return rs.Client.HMSet(
v.Name,
"rate", v.Rate,
"ask", v.Ask,
"bid", v.Bid,
"timestamp", fmt.Sprintf("%d", now.UnixNano())).Err()
}
func main() {
now := time.Now()
loc, err := time.LoadLocation("Europe/Moscow")
if err != nil {
panic(err)
}
rates, err := GetRates()
if err != nil {
panic(err)
}
fmt.Printf("%s\n", now.In(loc).Format("Mon 2 January 2006 15:04:05"))
storage, err := InitRedisStorage()
for _, v := range rates {
fmt.Printf("%s: Rate: %s. Bid: %s. Ask: %s.\n", v.Name, v.Rate, v.Bid, v.Ask)
err = storage.StoreRate(v, now)
if err != nil {
panic(err)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment