<目次>
学習履歴
前回は、Ginフレームワークに慣れるために、簡単なAPIを作成しました。
今回は、ginのControllerの実装とそのテストを行います。
前回
プロジェクト構成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
api ├── README.md ├── app │ ├── application.go │ └── url_mappings.go ├── controllers │ ├── ping_controller.go │ └── products │ └── products_controller.go ├── domain │ └── products │ └── product.go ├── main.go └── services └── products_service.go |
商品 structの構築
購入商品を表すProduct Structを作成します。domain/products/product.goに以下を追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// product.go package products import "time" // Product - defines product info uploaded by user type Product struct { ID uint64 `json:"id"` Name string `json:"name"` Detail string `json:"detail"` Price uint64 `json:"price"` Img []byte `json:"img"` CreatedAt time.Time UpdatedAt time.Time DeletedAt time.Time } |
APIを実装しているので、データ形式はJSONにしました。
json:"***"
は、リクエスト元のパラメータを指定しています。
例えば、以下のように指定できます。
1 |
curl -X POST localhost:8080/products -d '{"id": 1, "name":"coca cola", "price": 200}' |
次に、product.controller.goを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// products_controller.go package products import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/gin-gonic/gin" "github.com/gouser/money-boy/api/domain/products" ) // CreateProduct - Create product func CreateProduct(c *gin.Context) { var product products.Product bytes, err := ioutil.ReadAll(c.Request.Body) if err != nil { log.Println(err.Error()) return } if err := json.Unmarshal(bytes, &product); err != nil { log.Println(err.Error()) return } fmt.Println(string(bytes)) fmt.Println(err) c.JSON(http.StatusOK, product) } |
ginでは、ユーザーリクエストの情報がcontext(c)に入るため、c.Request.Bodyで取り出します。この時、ioutilパッケージのReadAllを使います。
その後、json.Unmarshalを使ってJSON構造を先ほど作った商品Structの形式にUnmarshalします。
でコンテナを立ち上げた後、Talend API Testerで動作確認をしてみましょう。docker-compose up

1 2 3 4 5 6 7 |
// パラメータとして使った値 { "id": 1, "name": "coca cola", "detail": "The coca cola is very very delicious drink", "price": 200 } |
ひとまず、動作はしてますね。この情報は後ほど、MySQLに登録するつもりです。
Controllerのテスト
せっかくなので、controllerのテストを書いてみましょう。
以下の記事を参考にしてください。
controllers/products配下に「products_controller.go」ファイルを作成します。
1 |
touch api/controllers/products/products_controller_test.go |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
// products_controller_test.go package products import ( "bytes" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/gouser/money-boy/api/domain/products" "github.com/stretchr/testify/assert" ) func TestCreateProductNoError(t *testing.T) { // Arrange --- p := products.Product{ID: 123, Name: "coca cola"} byteProduct, _ := json.Marshal(p) response := httptest.NewRecorder() c, _ := gin.CreateTestContext(response) c.Request, _ = http.NewRequest( http.MethodPost, "/products", bytes.NewBuffer(byteProduct), ) // Act --- CreateProduct(c) // Assert --- var product products.Product err := json.Unmarshal(response.Body.Bytes(), &product) assert.EqualValues(t, http.StatusOK, response.Code) assert.Nil(t, err) fmt.Println(product) assert.EqualValues(t, uint64(123), product.ID) } |
Arrangeでは、最初に送信データを用意しました。json.Marshal関数をを利用することで、GoのStructをjsonのbyteにデコードできます。
その後、レスポンスを記録するために「http.NewRecorder」でレスポンスを作成し、GinのCreateTestContextの引数として渡します。CreateTestContextにて、contextが作成できるようですね。
その後、contextのRequestパラメータに「送信形式」,「送信先URL」,「jsonデータ(byte)」をそれぞれ渡しています。
Actでは、テストしたい関数を使って、実際に処理を呼び出しています。
最後に、Assertでレスポンスのチェックを行なっています。ステータスコード200が返却されたか、errは発生していないか、戻り値は想定ないか、などの確認をしました。
テストを実行してみましょう。※apiコンテナは起動した状態でテストしてください。
1 2 3 |
$ docker container exec -it api sh -c "cd controllers && go test ./..." ? github.com/gouser/money-boy/api/controllers [no test files] ok github.com/gouser/money-boy/api/controllers/products 0.012s |
テストがPassしました!
CreateProduct Controllerはまだ未完成ですが、区切りがいいので今回はここまでにしましょう。
次回
次回は、例外処理の実装を行います。
コメントを残す
コメントを投稿するにはログインしてください。