エンジニア採用担当がプログラミング頑張る話【18日目/2ヶ月間】
こんにちは、@hiroki_maekawaです。
昨日に引き続き、今週のゴールを達成できるように頑張っていきたいと思います。
・RestfulAPIの構築
・http経由でデータのやりとり
・golangからmysqlに接続
今日の目標
・昨日の疑問点の解消
・JSON形式でレスポンスを受け取る
・golangからmysqlに接続する
1. 昨日の疑問点の解消
まずは昨日の疑問点の解消から。
【質問①】httpサーバーを立ち上げた後、同じターミナル内でコマンドを操作する方法はあるのか?
【回答①】方法はあるが、面倒なので別ターミナルを開くのがお勧め。
【質問②】1つのディレクトリに対してmain関数は1つしか使えない(別のディレクトリを作らないといけない)という意味なのか?(下記エラー参照)
main redeclared in this block
previous declaration at ./server.go9:6
【回答②】同一パッケージ内には同じ名前の関数を定義できないため、別のディレクトリを作る必要あり。
【質問③】curlを使ってPOSTリクエストはできたが、ブラウザで反映されていない理由は?
【回答③】"ブラウザ POSTリクエスト"で検索。アプリを用いる必要あり。
2. JSON形式でレスポンスを受け取る
毎回同じポート番号を使用していると、address already in useとなってしまうので、ググって出てきた80番とか8080番をポート番号を試してみたところ、通る番号と通らない番号がありました。(80番はNG、8080番はOK。)
これに関しては、80番(0~1000くらい?) までは利用用途が決まってるので簡単には使わせないよという風にmacがしているのでpermission deniedになってしまう。またポート番号の決め方は適当で大丈夫とのことでした。
ポート番号は8080番にして→構造体を書いて→JSON形式で出てくるように関数を書き換えて→go runして
package main
import (
"net/http"
"github.com/labstack/echo"
)
//User 構造体
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
e := echo.New()
e.GET("/save", save)
e.Logger.Fatal(e.Start(":8080"))
}
func save(c echo.Context) error {
u := new(User)
if err := c.Bind(u); err != nil {
return err
}
return c.JSON(http.StatusOK, u)
}
下記URLをブラウザに打つと、、
http://localhost:1323/save?name=Hiroki Maekawa&email=hiroki_maekawa@directpicks.co.jp
無事JSON形式で反映されました!
3. golangからmysqlに接続する
調べるとGoからMySQLに接続するためにはdatabase/sqlパッケージが使えるようなので、早速go getでインストールしました。
go get "github.com/go-sql-driver/mysql"
今回は試しに簡単な3行のデータベースを作成しました。
(base) HirokinoMacBook:~ hirokimaekawa$ mysql.server start
Starting MySQL
SUCCESS!
(base) HirokinoMacBook:~ hirokimaekawa$ mysql -u root -p;
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.19 Homebrew
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database gomysql;
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| gomysql |
| information_schema |
| mysql |
| performance_schema |
| scrapinggo |
| sys |
+--------------------+
6 rows in set (0.03 sec)
mysql> select database();
+------------+
| database() |
+------------+
| NULL |
+------------+
1 row in set (0.01 sec)
mysql> use gomysql
Database changed
mysql> create table gomysql(id int, name text, price int);
Query OK, 0 rows affected (0.02 sec)
mysql> desc gomysql;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | text | YES | | NULL | |
| price | int | YES | | NULL | |
+-------+------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into gomysql values (1, 'Apple', 300);
Query OK, 1 row affected (0.01 sec)
mysql> insert into gomysql values (2, 'Orange', 200);
Query OK, 1 row affected (0.02 sec)
mysql> insert into gomysql values (3, 'Grape', 500);
Query OK, 1 row affected (0.00 sec)
mysql> select * from gomysql;
+------+--------+-------+
| id | name | price |
+------+--------+-------+
| 1 | Apple | 300 |
| 2 | Orange | 200 |
| 3 | Grape | 500 |
+------+--------+-------+
3 rows in set (0.00 sec)
mysql>
その後、データベースの情報を取ってくるためにはsql.QueryRowやsql.Queryメソッドを使えばOKということが分かったので、コードを書いていきます。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
var id int
var name string
var price int
var err error
var db *sql.DB
//Fruits 構造体
type Fruits struct {
id int
name string
price int
}
func main() {
fruits := Fruits{}
//接続
db, err = sql.Open("mysql", "root:password@/gomysql")
if err != nil {
fmt.Println(err)
}
defer db.Close()
err = db.QueryRow("select id, name, price from gomysql WHERE id = 1").Scan(&fruits.id, &fruits.name, &fruits.price)
if err != nil {
fmt.Println(err)
}
fmt.Println(fruits.id, fruits.name, fruits.price)
}
先程作ったデータベースの1行目だけselectしてくるコードです。
go runで反映されていることが確認できました!
それでは次は複数行をselectしてきたいと思います。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
var id int
var name string
var price int
var err error
var db *sql.DB
//Fruits 構造体
type Fruits struct {
id int
name string
price int
}
func main() {
fruits := Fruits{}
//接続
db, err = sql.Open("mysql", "root:password@/gomysql")
if err != nil {
fmt.Println(err)
}
defer db.Close()
//複数行をselect -> ループ処理
rows, err := db.Query("select id, name, price from gomysql")
if err != nil {
fmt.Println(err)
}
//ループ処理 + Next関数
for rows.Next() {
err = rows.Scan(&fruits.id, &fruits.name, &fruits.price)
if err != nil {
fmt.Println(err)
}
fmt.Println(fruits)
}
}
ループ処理とNext関数を使って、複数行をselectしました。
無事3つ全てのデータを取得することができました。
テストコードまで書けてないですが、、とりあえず明日コードレビューをお願いしようと思います。
結構この記事にお世話になりました。
今日できるようになったこと
・GETリクエストでJSON形式のレスポンスを受け取る
・GoからMySQLに接続してデータを取得する(1行&複数行)
また下記、明日以降のやりたいことリストです。
やりたいことリスト
・GETリクエストして情報を取ってくる
・select文を実行してゲットした情報をJSON形式で返す
・受け取り用の構造体とレスポンス用の構造体を作って、JSON形式で受け取った値をJSON形式で返す
・CRUDまでできれば
・APIとRestfulAPIの違いとは?
・テストコード書かないと
さいごに
コードは色々なサイトを参考に書いているため、まだ何も参考にせずにスクラッチから書くことはできそうにありませんが、どの関数やコードを組み合わせればどういうことが実現できるのかが段々と分かってきました。
あとは数をこなせばもっと色々なパターンに対応できてくるんじゃないかなと思います。明日も頑張っていきたいと思います。
それではまた!