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

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

ただいまの
回答率

87.37%

【Go】echoでのUpdate実装で500エラーが返り実行できない

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,511

score 20

前提・実現したいこと

echoでのユーザー情報をUpdateする関数の実装

http://localhost:8888/api/v1/users/:id にてPUTでユーザーを更新しようとしています
{"name" : "なまえ"} という様なjsonを送ってとりあえず処理を実行したいと思ってます.

使用ツール

  • echo
  • gorm

発生している問題・エラーメッセージ

ルーティング・(送信している)JSON・dbのコネクションなどは,他のCRAETE・READ・DELETEが同じような処理で動いているのため問題ないと思います.

500: Internal Server Error

該当のソースコード

func UpdateUser() echo.HandlerFunc {
    return func(c echo.Context) (err error) {
        db, err := gorm.Open("mysql", "mysql設定")
        CheckConnectError(err) //エラーハンドリングの関数
        defer db.Close()

        user := new(model.User)
        if err := c.Bind(user); err != nil {
            return err
        }
        id, _ := strconv.Atoi(c.Param("id"))
        model.Users[id].Name = user.Name
        return c.JSON(http.StatusOK, "ok")
    }
}

model.Users[id].Nameは,modelパッケージのUsers変数をidで取ってきてNameに代入がしたくて書いています.
公式のドキュメントを参考にしました.

## model/user.go
~略
var (
    Users = map[int]*User{}
    Seq   = 1
)
略~

https://echo.labstack.com/cookbook/crud

処理がおかしいところはありますでしょうか.
よろしくお願いします

追記

ログはこのようになっております.

time:2019-07-26T15:37:53+09:00  host:::1        
forwardedfor:   req:-   
status:500      
method:PUT     
uri:/api/v1/users/3     
size:36 referer:        
ua:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36    
reqtime_ns:1895431      
cache:- runtime:-       
apptime:-       
vhost:localhost:8888    
reqtime_human:1.895431ms        
x-request-id:   host:localhost:8888

下記はかなり見辛いログですが,載せておきます.

{"time":"2019-07-26T15:37:53.480874+09:00","level":"-","prefix":"echo","file":"recover.go","line":"73","message":"[PANIC RECOVER] runtime error: invalid memory address or nil pointer dereference goroutine 50 [running]:\necho/middleware.RecoverWithConfig.func1.1.1(0x156b148, 0x1000, 0xc000060000, 0x160b140, 0xc0002b2120)\n\t/Users/kirohi/go/src/echo/middleware/recover.go:71 +0xf1\npanic(0x14cc0e0, 0x195b440)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/runtime/panic.go:522 +0x1b5\ngithub.com/ia17011/subsc/backend/api.UpdateUser.func1(0x160b140, 0xc0002b2120, 0x0, 0x0)\n\t/Users/kirohi/go/src/github.com/ia17011/subsc/backend/api/user.go:74 +0x19d\ngithub.com/labstack/echo.(*Echo).add.func1(0x160b140, 0xc0002b2120, 0xc0002160a0, 0xf)\n\t/Users/kirohi/go/src/github.com/labstack/echo/echo.go:505 +0x87\ngithub.com/ia17011/subsc/backend/api/middlewares.serverHeader.func1(0x160b140, 0xc0002b2120, 0x156b148, 0x1000)\n\t/Users/kirohi/go/src/github.com/ia17011/subsc/backend/api/middlewares/mainMiddlewares.go:25 +0x235\necho/middleware.RecoverWithConfig.func1.1(0x160b140, 0xc0002b2120, 0x0, 0x0)\n\t/Users/kirohi/go/src/echo/middleware/recover.go:78 +0xd5\necho/middleware.LoggerWithConfig.func2.1(0x160b140, 0xc0002b2120, 0x3, 0x4)\n\t/Users/kirohi/go/src/echo/middleware/logger.go:119 +0x1c0\ngithub.com/labstack/echo.(*Echo).ServeHTTP(0xc00028a000, 0x15fe860, 0xc0002bc000, 0xc0001e8a00)\n\t/Users/kirohi/go/src/github.com/labstack/echo/echo.go:616 +0x22d\nnet/http.serverHandler.ServeHTTP(0xc000226750, 0x15fe860, 0xc0002bc000, 0xc0001e8a00)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/net/http/server.go:2774 +0xa8\nnet/http.(*conn).serve(0xc00021e0a0, 0x15ff560, 0xc0001ecc00)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/net/http/server.go:1878 +0x851\ncreated by net/http.(*Server).Serve\n\t/usr/local/Cellar/go/1.12.5/libexec/src/net/http/server.go:2884 +0x2f4\n\ngoroutine 1 [IO wait]:\ninternal/poll.runtime_pollWait(0x1e91ea8, 0x72, 0x0)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/runtime/netpoll.go:182 +0x56\ninternal/poll.(*pollDesc).wait(0xc000232818, 0x72, 0x0, 0x0, 0x154be4a)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/internal/poll/fd_poll_runtime.go:87 +0x9b\ninternal/poll.(*pollDesc).waitRead(...)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/internal/poll/fd_poll_runtime.go:92\ninternal/poll.(*FD).Accept(0xc000232800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/internal/poll/fd_unix.go:384 +0x1ba\nnet.(*netFD).accept(0xc000232800, 0x30, 0x50, 0x50)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/net/fd_unix.go:238 +0x42\nnet.(*TCPListener).accept(0xc0002222f8, 0xc0f05880cb, 0xc000088000, 0xc00010dd00)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/net/tcpsock_posix.go:139 +0x32\nnet.(*TCPListener).AcceptTCP(0xc0002222f8, 0x100000001, 0xc00010dd30, 0x104c368)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/net/tcpsock.go:247 +0x48\ngithub.com/labstack/echo.tcpKeepAliveListener.Accept(0xc0002222f8, 0xc00010dd58, 0x10afda6, 0x5d3a9fc1, 0x1036bcf)\n\t/Users/kirohi/go/src/github.com/labstack/echo/echo.go:820 +0x2f\nnet/http.(*Server).Serve(0xc000226750, 0x15fe4e0, 0xc000222300, 0x0, 0x0)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/net/http/server.go:2859 +0x22d\ngithub.com/labstack/echo.(*Echo).StartServer(0xc00028a000, 0xc000226750, 0x0, 0x0)\n\t/Users/kirohi/go/src/github.com/labstack/echo/echo.go:707 +0x388\ngithub.com/labstack/echo.(*Echo).Start(...)\n\t/Users/kirohi/go/src/github.com/labstack/echo/echo.go:627\nmain.main()\n\t/Users/kirohi/go/src/github.com/ia17011/subsc/backend/main.go:16 +0x67\n\ngoroutine 51 [runnable]:\ndatabase/sql.(*DB).connectionOpener(0xc0002ca000, 0x15ff560, 0xc000220300)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/database/sql/sql.go:1000 +0xe8\ncreated by database/sql.OpenDB\n\t/usr/local/Cellar/go/1.12.5/libexec/src/database/sql/sql.go:670 +0x15e\n\ngoroutine 35 [runnable]:\ngithub.com/go-sql-driver/mysql.(*mysqlConn).startWatcher.func1(0xc0001f9080, 0xc0002c6120, 0xc0001f62a0)\n\t/Users/kirohi/go/src/github.com/go-sql-driver/mysql/connection.go:619 +0xbf\ncreated by github.com/go-sql-driver/mysql.(*mysqlConn).startWatcher\n\t/Users/kirohi/go/src/github.com/go-sql-driver/mysql/connection.go:616 +0xbe\n\ngoroutine 52 [runnable]:\ndatabase/sql.(*DB).connectionResetter(0xc0002ca000, 0x15ff560, 0xc000220300)\n\t/usr/local/Cellar/go/1.12.5/libexec/src/database/sql/sql.go:1013 +0x\n"}

api/user.goと送信しているjsonの追記

package api

import (
    "fmt"
    "net/http"
    "strconv"

    "github.com/ia17011/subsc/backend/model"
    "github.com/jinzhu/gorm"
    "github.com/labstack/echo"
    uuid "github.com/satori/go.uuid"
)

func getUUID() string {
    u, err := uuid.NewV4()
    if err != nil {
        fmt.Printf("Something went wrong: %s", err)
    }
    uu := u.String()
    return uu
}

func CreateUser() echo.HandlerFunc {
    return func(c echo.Context) (err error) {
        db, err := gorm.Open("mysql", "kirohi:cSbuS2mlGo##@/subsc?charset=utf8&parseTime=True&loc=Local")
        CheckConnectError(err)
        defer db.Close()
        user := &model.User{
            Id: model.Seq,
        }
        if err := c.Bind(&user); err != nil {
            return err
        }

        model.Users[user.Id] = user
        model.Seq++
        db.Create(&user)
        return c.JSON(http.StatusOK, user)
    }
}
func FindUserById() echo.HandlerFunc {
    return func(c echo.Context) (err error) {
        db, err := gorm.Open("mysql", "kirohi:cSbuS2mlGo##@/subsc?charset=utf8&parseTime=True&loc=Local")
        CheckConnectError(err)
        defer db.Close()
        user := model.User{}

        id := c.Param("id")
        db.First(&user, id)

        return c.JSON(http.StatusOK, user)
    }
}

func UpdateUser() echo.HandlerFunc {
    return func(c echo.Context) (err error) {
        db, err := gorm.Open("mysql", "kirohi:cSbuS2mlGo##@/subsc?charset=utf8&parseTime=True&loc=Local")
        CheckConnectError(err)
        defer db.Close()

        user := model.User{}
        if err = c.Bind(user); err != nil {
            return
        }
        id, _ := strconv.Atoi(c.Param("id"))
        db.Where("Id=?", id).Find(&user)

        user.Name = c.Param("name")

        fmt.Println(user.Name)
        // //model.Users[id].Name = "あああ"
        // //fmt.Println(model.Users[id])
        // return c.JSON(http.StatusOK, user)
        return c.JSON(http.StatusOK, "ok")
    }
}

func DeleteUser() echo.HandlerFunc {
    return func(c echo.Context) (err error) {
        db, err := gorm.Open("mysql", "kirohi:cSbuS2mlGo##@/subsc?charset=utf8&parseTime=True&loc=Local")
        CheckConnectError(err)
        defer db.Close()
        user := model.User{}

        name := c.Param("name")

        db.Where("name=?", name).Find(&user)
        db.Delete(&user)

        return c.NoContent(http.StatusOK)
    }
}

func NewUser(user *model.User) {
    db, err := gorm.Open("mysql", "kirohi:cSbuS2mlGo##@/subsc?charset=utf8&parseTime=True&loc=Local")
    CheckConnectError(err)
    defer db.Close()
    db.Create(user)
}

func FindUser(u *model.User) *model.User {
    db, err := gorm.Open("mysql", "kirohi:cSbuS2mlGo##@/subsc?charset=utf8&parseTime=True&loc=Local")
    CheckConnectError(err)
    defer db.Close()

    user := model.User{}
    db.Where(u).First(&user)
    return &user
}

json
http://localhost:8888/api/v1/users/3 というurlに対して,{ "name" : "あああ" } というbodyをContent-Type application/json,POSTで投げています.
ここでidが3であるユーザーの存在は,FindByUserID(),すなわちGETリクエストで確認できています.

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • nobonobo

    2019/07/25 13:57

    サーバーサイド側のログになにか出ていますでしょうか?そちらがあれば何が問題なのか予想しやすいです。

    キャンセル

  • kioak

    2019/07/26 15:41

    質問へ追記致しました.よろしくお願いいたします

    キャンセル

  • teikoku-penguin

    2019/07/26 20:19

    送っているjsonとapi/user.goも記載して下さい

    キャンセル

回答 2

0

return c.JSON(http.StatusOK, "ok")

としている所ですが、
jsonにできるstructではなくではなく文字列をわたしてしまってますね?

"ok" のかわりに model.Users[id] を指定してみてはいかがでしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/26 15:42

    ご回答ありがとうございます.何度か試してみましたが,500エラーから変化無しでした.

    キャンセル

  • 2019/07/27 08:54

    UpdateでもDBからデータを持ってこないとダメですね。

    DBアクセス関連コードがコメントアウトされているようですが、何か理由があったのでしょうか。

    キャンセル

  • 2019/07/31 03:11

    DBアクセス関連コードは何度か色々試してみて上手くいかなかったため置いていました.

    キャンセル

0

api/user.goのL74

 model.Users[id].Name = user.Name


とする時点ではmodel.Users[id]が存在しないように見えます
なので null pointer になっているのだと思います

再現
https://play.golang.org/p/4rNcjUEmsdb

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/31 03:13

    ご回答ありがとうございます.ご指摘通り,nullになっていました.このmapを作って処理するのはechoの公式のCRUDのレシピを参考にしたのですが,他のいい方法があれば教えていただけるとうれしいです

    キャンセル

  • 2019/07/31 03:23

    usersMap := make(map[int]User{}) など書き方は色々あると思いますが、ユーザー情報をPOST or PATCHでクライアントから受けてDBの内容を更新する処理では使わなくていいかなと思います
    どちらかと言えば、DBから複数のユーザーを取得した時になにかしらの処理をする場合に扱いやすくするなどで使うかなと思います

    キャンセル

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

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る