サーバーからデータベースを扱う
Echo を使い、データベースからデータを取得するサーバーアプリケーションを作りましょう。
go
package main
import (
"database/sql"
"errors"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
"github.com/labstack/echo/v4"
)
type City struct {
ID int `json:"id,omitempty" db:"ID"`
Name string `json:"name,omitempty" db:"Name"`
CountryCode string `json:"countryCode,omitempty" db:"CountryCode"`
District string `json:"district,omitempty" db:"District"`
Population int `json:"population,omitempty" db:"Population"`
}
var (
db *sqlx.DB
)
func main() {
jst, err := time.LoadLocation("Asia/Tokyo")
if err != nil {
log.Fatal(err)
}
conf := mysql.Config{
User: os.Getenv("DB_USERNAME"),
Passwd: os.Getenv("DB_PASSWORD"),
Net: "tcp",
Addr: os.Getenv("DB_HOSTNAME") + ":" + os.Getenv("DB_PORT"),
DBName: os.Getenv("DB_DATABASE"),
ParseTime: true,
Collation: "utf8mb4_unicode_ci",
Loc: jst,
}
_db, err := sqlx.Open("mysql", conf.FormatDSN())
if err != nil {
log.Fatal(err)
}
log.Println("connected")
db = _db
e := echo.New()
e.GET("/cities/:cityName", getCityInfoHandler)
e.Start(":8080")
}
func getCityInfoHandler(c echo.Context) error {
cityName := c.Param("cityName")
log.Println(cityName)
var city City
err := db.Get(&city, "SELECT * FROM city WHERE Name=?", cityName)
if errors.Is(err, sql.ErrNoRows) {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("No such city Name = %s", cityName))
}
if err != nil {
log.Printf("DB Error: %s", err)
return echo.NewHTTPError(http.StatusInternalServerError, "internal server error")
}
return c.JSON(http.StatusOK, city)
}
都市が見つかったら200
を、見つからなかったら404
を返しています。 Postman からリクエストを送ってみましょう。
画像のように返ってきたら成功です。
自分が好きな都市の情報を取得する API を叩いて、そのレスポンスのスクリーンショットを講習会チャンネルに投稿しましょう。
基本問題
都市を追加する API を追加してみましょう。
ヒント 1
都市を追加するということはクライアントから情報を受け取る必要があります。このようなときは、どのメソッドを使えばいいでしょうか。
ヒント 2
メソッドはPOST
を使いましょう。リクエストボディには JSON を使いましょう。どのようにすれば JSON を扱えたでしょうか。
答え
main
関数内部
go
e := echo.New()
e.GET("/cities/:cityName", getCityInfoHandler)
e.POST("/cities", postCityHandler) //[!code ++]
e.Start(":8080")
}
postCityHandler
関数を定義
go
func postCityHandler(c echo.Context) error { //[!code ++]
var city City //[!code ++]
err := c.Bind(&city) //[!code ++]
if err != nil { //[!code ++]
return echo.NewHTTPError(http.StatusBadRequest, "bad request body") //[!code ++]
} //[!code ++]
//[!code ++]
result, err := db.Exec("INSERT INTO city (Name, CountryCode, District, Population) VALUES (?, ?, ?, ?)", city.Name, city.CountryCode, city.District, city.Population) //[!code ++]
if err != nil { //[!code ++]
log.Printf("DB Error: %s", err) //[!code ++]
return echo.NewHTTPError(http.StatusInternalServerError, "internal server error") //[!code ++]
} //[!code ++]
//[!code ++]
id, _ := result.LastInsertId() //[!code ++]
city.ID = int(id) //[!code ++]
//[!code ++]
return c.JSON(http.StatusCreated, city) //[!code ++]
} //[!code ++]
架空の都市や実在する都市を Postman から追加して、レスポンスのスクリーンショットを講習会チャンネルに投稿しましょう。
応用問題
さまざまな API を作ってみましょう。
- 例
- 国の情報を取得する
- 都市をすべて取得する
- 既にある都市や国の情報を変更する