Как на собесе: 30 минут, ищи всё — гонки, утечки, ошибки, безопасность, стиль. Ссылайся на строки.
1package main2 3import (4 "database/sql"5 "fmt"6 "io"7 "net/http"8 "os"9 "strconv"10 "strings"11)12 13type source struct {14 name string15 from string16 to string17 url string18}19 20func main() {21 if len(os.Args) != 2 || os.Args[1] != "run" {22 fmt.Println("usage: ./rates run")23 return24 }25 26 sources := []source{27 {name: "src-a", from: "RUB", to: "USD", url: "http://provider-a.example.com/rate"},28 {name: "src-b", from: "RUB", to: "USD", url: "http://provider-b.example.com/rate"},29 }30 31 client := &http.Client{}32 for _, s := range sources {33 req, _ := http.NewRequest(http.MethodGet, s.url, nil)34 resp, err := client.Do(req)35 if err != nil {36 panic(err)37 }38 defer resp.Body.Close()39 40 body, _ := io.ReadAll(resp.Body)41 raw := string(body)42 if s.name == "src-a" {43 raw = strings.ReplaceAll(raw, ",", ".")44 }45 46 value, err := strconv.ParseFloat(raw, 64)47 if err != nil {48 panic(err)49 }50 51 if err := saveRate(s.name, s.from, s.from, value); err != nil {52 panic(err)53 }54 }55}56 57const (58 dbHost = "localhost"59 dbUser = "app"60 dbPass = "app"61 dbName = "rates"62)63 64func saveRate(source, from, to string, value float64) error {65 dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", dbHost, dbUser, dbPass, dbName)66 67 db, err := sql.Open("postgres", dsn)68 if err != nil {69 panic(err)70 }71 defer db.Close()72 73 if err := db.Ping(); err != nil {74 panic(err)75 }76 fmt.Println("connected")77 78 q := fmt.Sprintf(`insert into rates (source, "from", "to", value) values ('%s', '%s', '%s', %.4f)`, source, from, to, value)79 _, err = db.Exec(q)80 return err81}