카테고리 없음

golang REST API / go언어 REST API 서버 #4 DB연동 Select / METHOD GET

미래의 고 2023. 3. 18. 22:21

다음과 같은 구조로 계속 포스팅을 하려 합니다.

POST /device       -> Device 아이템 추가 (포스팅 완료)  / curl -X POST -H "Content-Type: application/json" -d '{"name":"iPhone19","mac":"ff:11:11:22:33:11"}' http://localhost:8000/v1.0/device
GET /device        -> Device 아이템 리스트 조회 (진행중) / curl -X GET -H "Content-Type: application/json" -d '{}' http://localhost:8000/v1.0/device
GET /device/{pk}   -> Device 아이템 조회
PUT /device/{pk}    -> Device 아이템 수정
DELETE /device/{pk} -> Device 아이템 삭제
 
현재까지 다음과 같이 데이터가 있습니다. IDEA에서 테이블 확인한 결과입니다.
이전에, 터미널에서 보면 binary가 깨져 보이죠? IDEA에서는 헥사로 잘 보입니다.
하지만 이번 포스팅엔 binary와 아무런 상관없습니다.
IDEA에서 Database Browser 보다가 갑자기 생각나서 찍어봤습니다.
 
 
mariaDB에서 바이너리를 text로 디코드 해서 보려면 hex 함수를 쓰면 됩니다.
 

이제 저 데이터중에 '아이템 리스트 조회'를 포스팅 해보겠습니다.

 
package main

import (
   "database/sql"
   "encoding/json"
   "fmt"
   _ "github.com/go-sql-driver/mysql"
   "net/http"
   "strings"
)

type Device struct {
   Id   int    `json:"id"`
   Name string `json:"name"`
   Mac  string `json:"mac"`
}

const (
   httpPort       = ":8000"
   driverName     = "mysql"
   dataSourceName = "TheGolangOfFuture:TheGolangOfFuture@tcp(127.0.0.1:3306)/TheGolangOfFuture"
)

func device(res http.ResponseWriter, req *http.Request) {
   db, err := sql.Open(driverName, dataSourceName)
   if err != nil {
      fmt.Printf(err.Error())
      res.WriteHeader(http.StatusInternalServerError)
      return
   }
   defer db.Close()

   if req.Method == http.MethodPost {
      var device Device
      err := json.NewDecoder(req.Body).Decode(&device)
      if err != nil {
         res.WriteHeader(http.StatusBadRequest)
         return
      }

      fmt.Printf("[POST] Name=%s,Mac=%s\n", device.Name, device.Mac) // DB insert

      tmpMac := strings.Replace(device.Mac, ":", "", -1) // 맥은 ":", "-", "." 등 여러가지가 올 수 있지만 예제에서는 ":"만 처리 하겠습니다.

      query := fmt.Sprintf("INSERT INTO Device (name, mac, mac_bin) VALUES('%s', '%s', unhex('%s'))", device.Name, device.Mac, tmpMac) // 이코드는 사실상 너무나 취약합니다.
      insert, err := db.Query(query)
      if err != nil {
         fmt.Println(err.Error())
         res.WriteHeader(http.StatusInternalServerError)
         return
      }
      defer insert.Close()

      res.Header().Set("Content-Type", "application/json")
      res.WriteHeader(http.StatusOK)
      json.NewEncoder(res).Encode(map[string]interface{}{
         "success":  true,
         "messages": fmt.Sprintf("Post success : %s", device.Mac),
      })
   } else if req.Method == http.MethodGet {
      // 페이징은 생략하겠습니다.
      // 1개 Item Get은 다음 포스팅에

      rs, err := db.Query("SELECT id, name FROM Device")
      if err != nil {
         fmt.Println(err.Error())
         res.WriteHeader(http.StatusInternalServerError)
         return
      }
      defer rs.Close()

      var result []Device
      for rs.Next() {
         var d Device
         err := rs.Scan(&d.Id, &d.Name)
         if err != nil {
            fmt.Println(err.Error())
            res.WriteHeader(http.StatusInternalServerError)
            return
         }
         result = append(result, d)
      }

      res.Header().Set("Content-Type", "application/json")
      res.WriteHeader(http.StatusOK)
      json.NewEncoder(res).Encode(map[string]interface{}{
         "success": true,
         "data":        result,
      })

   } else {
      res.WriteHeader(http.StatusMethodNotAllowed) // 나머지 메소드는 허용안함
   }

}

func main() {
   fmt.Println("Start WEB", httpPort)
   http.HandleFunc("/v1.0/device", device)
   http.ListenAndServe(httpPort, nil)
}