GO gorm DB作成 INSERT JSONUnmarshal Mysql

こんにちは！　GO学習中です！

今回はgormでinsertしてみたいと思います！

[データは前回getしたapi](https://qiita.com/13Slhr77Cgzn892/items/22d4670a201fff221b61)
のデータを使用します。

DB自体をGOから作成した記事は[こちら](https://qiita.com/13Slhr77Cgzn892/items/7c28e4079e9b7407df6a)です。


では始めていきたいと思います。


### mysql.go

```go
// root/app/models/fgi.go
package mysql

import (
	"database/sql"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
)

// SQLConnect DB接続
func SQLConnect() (database *gorm.DB, err error) {
	DBMS := "mysql"
	USER := "root"
	PASS := ""
	PROTOCOL := "tcp(localhost:3306)"
	DBNAME := "テーブル名"

	CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo"
	return gorm.Open(DBMS, CONNECT)
}

```
ここではDBはすでに作成しているものとします。
gormとはGOのORMパッケージです。

SQLConnect()の関数ではDBの情報を宣言して、

`return gorm.Open(DBMS, CONNECT)`

とすることでdbと接続しています。
DB情報はConfigなどにまとめたほうが良いかもしれません。今回はルートユーザーで行なっていきます。


### fgi/fgi.go

こちらは[冒頭紹介した記事](https://qiita.com/13Slhr77Cgzn892/items/22d4670a201fff221b61)
でgetしているapiのファイルです。上記の記事ではgetしただけでしたが、こちらでは
json.Unmarshalをすることで、用意した構造体に格納しています。

構造体はこちらの [json-to-go](https://mholt.github.io/json-to-go/)
というサイトで簡単に用意できます。

左側にapiのjsonを貼り付けるとコード内のstructを用意してくれます。


```go

package fgi

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
)

// APIClientFgi api情報格納
type APIClientFgi struct {
	key        string
	host       string
	httpClient *http.Client
}

// New struct生成
func New(key, host string) *APIClientFgi {
	fgiClient := &APIClientFgi{key, host, &http.Client{}}
	return fgiClient
}

// StructFgi fgi格納
type StructFgi struct {
	Fgi struct {
		Current struct {
			Value     int    `json:"value"`
			ValueText string `json:"valueText"`
		} `json:"now"`
		PreviousClose struct {
			Value     int    `json:"value"`
			ValueText string `json:"valueText"`
		} `json:"previousClose"`
		OneWeekAgo struct {
			Value     int    `json:"value"`
			ValueText string `json:"valueText"`
		} `json:"oneWeekAgo"`
		OneMonthAgo struct {
			Value     int    `json:"value"`
			ValueText string `json:"valueText"`
		} `json:"oneMonthAgo"`
		OneYearAgo struct {
			Value     int    `json:"value"`
			ValueText string `json:"valueText"`
		} `json:"oneYearAgo"`
	} `json:"fgi"`
}

// GetFgi api実行
func (fgi *APIClientFgi) GetFgi() (StructFgi, error) {

	url := "https://fear-and-greed-index.p.rapidapi.com/v1/fgi"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("x-rapidapi-host", fgi.host)
	req.Header.Add("x-rapidapi-key", fgi.key)

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return StructFgi{}, nil
	}

	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return StructFgi{}, nil
	}

	var fgiStruct StructFgi
	if err := json.Unmarshal(body, &fgiStruct); err != nil {
		log.Fatal(err)
	}

	return fgiStruct, nil
}
```

json-to-goで生成したstructを呼び出しjson.Unmarshalでstructに格納しています。


### models/fgi.go

このファイルでは上記でstructに格納したapi情報を展開してDBにINSERTしていきます。

```go
package models

import (
	"fmt"
	"index-indicator-apis/mysql"
	"time"

	"index-indicator-apis/config"
	"index-indicator-apis/fgi"
)

const (
	tableNameFgis = "fgis"
)

// Fgis 日足格納
type Fgis struct {
	CreatedAt time.Time `json:"created_at,omitempty"`
	NowValue  int       `json:"now_value,omitempty"`
	NowText   string    `json:"now_text,omitempty"`
	PcValue   int       `json:"pc_value,omitempty"`
	PcText    string    `json:"pc_text,omitempty"`
	OneWValue int       `json:"one_w_value,omitempty"`
	OneWText  string    `json:"one_w_text,omitempty"`
	OneMValue int       `json:"one_m_value,omitempty"`
	OneMText  string    `json:"one_m_text,omitempty"`
	OneYValue int       `json:"one_y_value,omitempty"`
	OneYText  string    `json:"one_y_text,omitempty"`
}

//initFgis マイグレーション
func initFgis() {
	var err error
	db, err := mysql.SQLConnect()
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()
	db.AutoMigrate(&Fgis{})
}

// NewFgis fgi.StructFgiを受け取り、Fgisに変換して返す


func NewFgis(f fgi.StructFgi) *Fgis {
	createdAt := time.Now()
	nowValue := f.Fgi.Current.Value
	nowText := f.Fgi.Current.ValueText
	pcValue := f.Fgi.PreviousClose.Value
	pcText := f.Fgi.PreviousClose.ValueText
	oneWValue := f.Fgi.OneWeekAgo.Value
	oneWText := f.Fgi.OneWeekAgo.ValueText
	oneMValue := f.Fgi.OneMonthAgo.Value
	oneMText := f.Fgi.OneMonthAgo.ValueText
	oneYValue := f.Fgi.OneYearAgo.Value
	oneYText := f.Fgi.OneYearAgo.ValueText

	return &Fgis{
		createdAt,
		nowValue,
		nowText,
		pcValue,
		pcText,
		oneWValue,
		oneWText,
		oneMValue,
		oneMText,
		oneYValue,
		oneYText,
	}
}

// Create NewFgisをsaveする
func (f *Fgis) Create() error {
	db, err := mysql.SQLConnect()
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()
	db.Create(&f)
	return err
}

// CreateNewFgis migration後にapiを叩きdbに保存する
func CreateNewFgis() error {
	// initFgis()　migration
	fgiClient := fgi.New(config.Config.FgiAPIKey, config.Config.FgiAPIHost)
	f, err := fgiClient.GetFgi()
	if err != nil {
		return err
	}
	fgi := NewFgis(f)
	fmt.Println(fgi)
	fmt.Println(fgi.Create())
	return err
}

```

initFgis()ではgormのメソッドをつかってマイグレーションしています。
apiの情報を先ほどstructに格納したので、それを展開してさらに展開したvalueを格納するstructを用意するということですね。
 `db.AutoMigrate(&Fgis{})` こちらがgormのメソッド AutoMigrateメソッドです。
事前に用意した構造体の名前をテーブル名としてマイグレーションしてくれます。この場合だと
fgisというテーブルがmysqlに作成されます。

`func NewFgis(f fgi.StructFgi) *Fgis{}`
こちらではapiのデータを格納している StructFgiの中身を展開してINSERTするために用意した構造体（マイグレーションした）の中に格納してます。

`func (f *Fgis) Create() error {}`
こちらのメソッドではmysqlファイルで作成した関数のSQLConnect()でdbと接続後に

`db.Create(&f)`
とすることでINSERTを実現しています。 .Createがgormのメソッドです。　.Create(&struct)とすることでテーブル名と対応しているstructの情報をINSERTしてくれます。

最後に`CreateNewFgis()`で用意した関数とメソッドを実行しています。

この関数をmain.goから呼び出せば無事に実行されることができました。

* gormでは主キーとなるIDは自動で生成されるので宣言する必要はありません。


以上です！