質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
DI (Dependence Injection)

DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

1回答

917閲覧

Golang DB 依存性の注入

Shika_Tech

総合スコア13

DI (Dependence Injection)

DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2021/01/17 01:16

編集2021/01/17 01:20

Golangを独学で学習しているものです。
ぜひお力を貸して頂けると幸いです。

● 現在の状況
golangでDIを実装したい(モックテストを実現するため)

● 困っていること
参考書などを引用してコードを実装↓
gormを使用しており、DIするためにハンドラーにdbを渡した。

main.go

main.go

1 2func signupHandler(user models.UserService) http.HandlerFunc { 3 return func(w http.ResponseWriter, r *http.Request) { 4 var u models.User 5 json.NewDecoder(r.Body).Decode(&u) 6 7 name := u.UserName 8 email := u.Email 9 pass := u.Password 10 11 if name == "" { 12 apiError(w, "UserName is required", http.StatusBadRequest) 13 return 14 } 15 if email == "" { 16 apiError(w, "Email is required", http.StatusBadRequest) 17 return 18 } 19 if pass == "" { 20 apiError(w, "Password is required", http.StatusBadRequest) 21 return 22 } 23 24 if err := user.CreateUser(name, email, pass); err != nil { 25 apiError(w, "username or email are duplicated", http.StatusConflict) 26 return 27 } 28 29 apiError(w, "success", http.StatusCreated) 30 return 31 } 32} 33 34func userDeleteHandler(user models.UserService) http.HandlerFunc { 35 return func(w http.ResponseWriter, r *http.Request) { 36 var u models.User 37 json.NewDecoder(r.Body).Decode(&u) 38 39 id, err := strconv.Atoi(path.Base(r.URL.Path)) 40 if err != nil { 41 apiError(w, "cloud not find user", http.StatusNotFound) 42 return 43 } 44 err = user.DeleteUser(id, u.Password) 45 if err != nil { 46 apiError(w, err.Error(), http.StatusBadRequest) 47 return 48 } 49 apiError(w, "success", http.StatusOK) 50 return 51 } 52} 53 54func StartWebServer() error { 55 db, err := db.SQLConnect() 56 if err != nil { 57 panic(err.Error()) 58 } 59 defer db.Close() 60 61 r := mux.NewRouter() 62 http.Handle("/", r) 63 64 // users 65 r.HandleFunc("/users", signupHandler(&models.User{DB: db})).Methods("POST") 66 r.HandleFunc("/users/{id:[0-9]+}", userDeleteHandler(&models.User{DB: db})).Methods("DELETE") 67 68 return http.ListenAndServe(fmt.Sprintf(":%d", config.Config.Port), nil) 69}

models.go

1type UserService interface { 2 CreateUser(name string, email string, pass string) (err error) 3 DeleteUser(id int, pass string) (err error) 4} 5 6// User 構造体 7type User struct { 8 DB *gorm.DB 9 ID int `json:"id,omitempty" gorm:"primaryKey,unique"` 10 UserName string `json:"user_name,omitempty" gorm:"unique"` 11 Email string `json:"email,omitempty" gorm:"unique"` 12 Password string `json:"password,omitempty"` 13 CreatedAt time.Time `json:"created_at,omitempty"` 14 UpdatedAt time.Time `json:"updated_at,omitempty"` 15} 16 17// CreateUser user登録 18func (user *User) CreateUser(name, email, pass string) (err error) { 19 user.ID = 0 //gorm auto increment 20 user.UserName = name 21 user.Email = email 22 user.CreatedAt = time.Now() 23 user.UpdatedAt = time.Now() 24 25 hash, err := bcrypt.GenerateFromPassword([]byte(pass), 10) 26 if err != nil { 27 log.Fatal(err) 28 } 29 user.Password = string(hash) 30 31 if err := user.DB.Create(&user).Error; err != nil { 32 return err 33 } 34 35 return 36} 37 38func (user *User) DeleteUser(id int, pass string) (err error) { 39 if err := user.DB.First(&user, id).Error; err != nil { 40 return err 41 } 42 43 if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(pass)); err != nil { 44 return err 45 } 46 47 if err := user.DB.Delete(&user).Error; err != nil { 48 return err 49 } 50 return nil 51}

エラー

apiを叩くと1度しか成功しない。
1度目に叩い情報が構造体に残ったままになってしまう。

質問

apiを叩くと1回目の処理は成功するが、2回目以降の処理は1度目に叩いた情報が残っているので毎回初期化しないといけないのでしょうか?
CreateUserメソッドではIDに0を渡すことで無理やりIDを初期化しております。
ID = 0 を書かなければ user.ID duplicateのエラーが出てしまいます。

DIしない場合はSQL処理の度にdb.Close()しているため毎回初期化されると予想しております。

箇条書きで羅列してしまいましたが、以上でぜひお力をお借りしたいです>_<
どうぞよろしくお願いいたします!

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

gormの「モデル定義の構造体型」はデータベースの1レコードごとに「インスタンス化と破棄」されることを前提とした作りになっています。ひとつのインスタンスを持ち回って使い回すことは想定されていません。
なので、モデルにDBインスタンスをもたせるのもミスマッチだと思います。

投稿2021/01/17 21:37

nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Shika_Tech

2021/01/17 23:22

nobonobo様 ご指摘頂きありがとうございます。 > gormの「モデル定義の構造体型」はデータベースの1レコードごとに「インスタンス化と破棄」 > モデルにDBインスタンスをもたせるのもミスマッチ なるほどですね。ここは標準のパッケージで書き直すか、コンストラクタインジェクション? という方法で実装するのが良いでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問