Skip to content

Instantly share code, notes, and snippets.

@tomsato
Last active January 9, 2023 03:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomsato/64c22ebf60927fb17a5ec2bb5e595c13 to your computer and use it in GitHub Desktop.
Save tomsato/64c22ebf60927fb17a5ec2bb5e595c13 to your computer and use it in GitHub Desktop.
Golangのnet/httpを利用したサンプルAPI
package main
import (
"database/sql"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
_ "github.com/go-sql-driver/mysql"
)
// 環境変数の定義
type appEnvironment struct {
username string
password string
}
// レスポンスJsonの定義
type apiRequestResponse struct {
Code int `json:"code"`
Message string `json:"message"`
}
// DBのフィールド
type person struct {
id int
name string
}
func main() {
http.HandleFunc("/request", makeHandler(requestHandler))
http.HandleFunc("/person", makeHandler(personHandler))
http.ListenAndServe(":8080", nil)
}
// handlerに共通の変数を渡すため、3つの引数をもつfunctionを引数にとり、func(ResponseWriter, *Request)を返す
func makeHandler(fn func(http.ResponseWriter, *http.Request, appEnvironment)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fn(w, r, getAppEnvironment())
}
}
// APIを叩いてレスポンスを返す
func requestHandler(w http.ResponseWriter, r *http.Request, env appEnvironment) {
// headerセット
w.Header().Set("Content-Type", "application/json; charset=utf-8")
// methodバリデーション
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write(createResponsJson(&apiRequestResponse{Code: 2001, Message: "Method not allowed."}))
return
}
// クエリパラメータ取得&バリデーションチェック
paramKey := r.URL.Query().Get("key")
if len(paramKey) == 0 {
w.WriteHeader(http.StatusBadRequest)
w.Write(createResponsJson(&apiRequestResponse{Code: 2002, Message: "key paramater not found."}))
return
}
// HTTPリクエストを行い結果をログに出力
resp, _ := http.Get("http://httpbin.org/get?key=" + paramKey)
if resp == nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write(createResponsJson(&apiRequestResponse{Code: 2003, Message: "HTTP Request failed."}))
return
}
defer resp.Body.Close()
byteArray, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("log: %s", byteArray)
// レスポンスデータの生成
w.Write(createResponsJson(&apiRequestResponse{Code: 2000, Message: "OK"}))
}
// DBを叩いてレスポンスを返す
func personHandler(w http.ResponseWriter, r *http.Request, env appEnvironment) {
// headerセット
w.Header().Set("Content-Type", "application/json; charset=utf-8")
// methodバリデーション
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write(createResponsJson(&apiRequestResponse{Code: 2001, Message: "Method not allowed."}))
return
}
// クエリパラメータ取得&バリデーションチェック
paramUser := r.URL.Query().Get("user")
if len(paramUser) == 0 {
w.WriteHeader(http.StatusBadRequest)
w.Write(createResponsJson(&apiRequestResponse{Code: 2002, Message: "user paramater not found."}))
return
}
// DBからデータを取得して結果をログに出力
db, err := sql.Open("mysql", "root:"+env.password+"@/"+env.username)
if err != nil {
panic(err.Error())
}
defer db.Close()
rows, err := db.Query("SELECT * FROM person")
if err != nil {
panic(err.Error())
}
defer rows.Close()
for rows.Next() {
var person person
err := rows.Scan(&person.id, &person.name)
if err != nil {
panic(err.Error())
}
fmt.Println(person.id, person.name)
}
err = rows.Err()
if err != nil {
panic(err.Error())
}
// レスポンスデータの生成
w.Write(createResponsJson(&apiRequestResponse{Code: 2000, Message: "OK"}))
}
// 都度Marshalしてエラーチェックするのは面倒なので
func createResponsJson(a *apiRequestResponse) []byte {
json, err := json.Marshal(*a)
if err != nil {
panic("json can not marshal.")
}
return json
}
// 環境変数を取得
func getAppEnvironment() appEnvironment {
if len(os.Getenv("DB_USERNAME")) == 0 || len(os.Getenv("DB_PASSWORD")) == 0 {
panic("appEnvironment not setting.")
}
return appEnvironment{
username: os.Getenv("DB_USERNAME"),
password: os.Getenv("DB_PASSWORD"),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment