웹 서버를 구축할떄의 기준점이라고 할수 있는 RESTful API를 활용한 서버를 공부하였습니다.
대부분 HTTP메서드를 다루는 방법에 대해서 학습이 진행되었습니다.
일단 기본적으로 Go의 내부 패키지를 활용하여 만들수도 있습니다.
하지만 번거로운 작업이 되기 떄문에 RESTful API를 쉽게 만들 수 있도록 지원해주는 gorilla/mux
패키지를 사용 해 보았습니다.
go get -u github.com/gorilla/mux
를 통해서 설치해 줍니다.
go mod, build
를 적용하여 모듈을 초기화 시켜주어야 합니다.
package main
import (
"encoding/json"
"net/http"
"sort"
"github.com/gorilla/mux"
)
type Student struct {
Id int
Name string
Age int
Score int
}
var students map[int]Student
var lastId int
func MakeWebHandler() http.Handler {
mux := mux.NewRouter()
mux.HandleFunc("/students", GetStudentListHandler).Methods("GET")
// 함수가 아니 라는 점을 유의
students = make(map[int]Student)
students[1] = Student{1, "aaa", 16, 87}
students[2] = Student{2, "bbb", 18, 98}
lastId = 2
return mux
}
type Students []Student
func (s Students) Len() int {
return len(s)
}
func (s Students) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s Students) Less(i, j int) bool {
return s[i].Id < s[j].Id
}
func GetStudentListHandler(w http.ResponseWriter, r *http.Request) {
list := make(Students, 0)
for _, student := range students {
list = append(list, student)
}
sort.Sort(list)
json.NewEncoder(w).Encode(list)
}
func main() {
http.ListenAndServe(":3000", MakeWebHandler())
}
천천히 한번 다루어 보겠습니다.
일단 기본적으로 main()함수가 먼저 작동을 하게 되기 떄문에 MakeWebHandler()
함수가 작동을 하게 됩니다.
그러면 이전에 학습했던것과는 다르게 NewRouter
가 사용이 가능하고 이를 활용하여 Router를 만들어 줍니다.
NewServeMux
를 활용 하였지만Methods
를 따로 편하게 지정을 할수 없기 떄문에 이전에 설치한 외부 모듈을 활용하여 간단하게 구성을 합니다.이후 경로를 설정해 주고 해당 경로에 해당하는 Http메서드를 지정해 줍니다.
이후 데이터 값들을 입력해 줌으로써 준비가 끝납니다.
이 부분의 작동 방식에 대해서는 Youtube를 통해서 다루어 보겠습니다.
이제 특정 Id에 해당하는 학생 데이터를 반환하는 핸들러를 만들어 보겠습니다.
package main
import (
"encoding/json"
"fmt"
"net/http"
"sort"
"strconv"
"github.com/gorilla/mux"
)
type Student struct {
Id int
Name string
Age int
Score int
}
var students map[int]Student
var lastId int
func MakeWebHandler() http.Handler {
mux := mux.NewRouter()
mux.HandleFunc("/students", GetStudentListHandler).Methods("GET")
mux.HandleFunc("/students/{id:[0-9]+}", GetStudentHandler).Methods("GET")
students = make(map[int]Student)
students[1] = Student{1, "aaa", 16, 87}
students[2] = Student{2, "bbb", 18, 98}
lastId = 2
return mux
}
type Students []Student
func (s Students) Len() int {
return len(s)
}
func (s Students) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s Students) Less(i, j int) bool {
return s[i].Id < s[j].Id
}
func GetStudentListHandler(w http.ResponseWriter, r *http.Request) {
list := make(Students, 0)
for _, student := range students {
fmt.Println(student)
list = append(list, student)
}
sort.Sort(list)
json.NewEncoder(w).Encode(list)
}
func GetStudentHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) //id값을 가져오는 방법
fmt.Println(vars)
id, _ := strconv.Atoi(vars["id"])
student, ok := students[id]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(student)
}
func main() {
http.ListenAndServe(":3000", MakeWebHandler())
}
특정 데이터를 가져올떄 사용을 할수 있는 방법 입니다.
mus.Vars
에 인자를 넣어줌으로써 들어오는 데이터를 확인이 가능하고 이후 students부분에서 동일한 Id값이 있는지를 확인함으로써 작동이 됩니다.
드디어 post요청을 하는 방법 입니다.
전체 코드보다는 추가해야할 코드를 적음으로써 다루어 보겠습니다.
일단 핸들러를 추가해 줍니다.
mux.HandleFunc("/student", PostStudentHandler).Methods("POST")
그후 핸들러에 추가된 함수를 추가해 줍니다.
func PostStudentHandler(w http.ResponseWriter, r *http.Request){
var student Student
err := json.NewDecoder(r.Body).Decode(&student)
if err != nil{
w.WriteHeader(http.StatusBadRequest)
return
}
lastId++
student.Id = lastId
students[lastId] = student
w.WriteHeader(http.StatusCreated)
}
POST요청이기 떄문에 들어오는 데이터를 담고 이후 변수값에 추가해 주는 방법으로 작동을 하게 됩니다.
그럼 반대로 삭제하는 방법에 대해서 다루어 보겠습니다.
먼저 핸들러를 추가해 줍니다.
mux.HandleFunc("/students/{id:[0-9]+}", DeleteStudentHandler).Methods("DELETE")
이후 마찬가지로 사용할 함수를 추가해 줍니다.
func DeleteStudentHandler(w http.ResponseWriter, r *http.Request){
vars:=mux.Vars(r)
id, _ :=strconv.Atoi(vars["id"])
_,ok := students[id]
if !ok{
w.WriteHeader(http.StatusNotFound)
return
}
delete(students, id)
w.WriteHeader(http.StatusOK)
}
package main
import (
"encoding/json"
"fmt"
"net/http"
"sort"
"strconv"
"github.com/gorilla/mux"
)
type Student struct {
Id int
Name string
Age int
Score int
}
var students map[int]Student
var lastId int
func MakeWebHandler() http.Handler {
mux := mux.NewRouter()
mux.HandleFunc("/students", GetStudentListHandler).Methods("GET")
mux.HandleFunc("/students/{id:[0-9]+}", GetStudentHandler).Methods("GET")
mux.HandleFunc("/student", PostStudentHandler).Methods("POST")
mux.HandleFunc("/students/{id:[0-9]+}", DeleteStudentHandler).Methods("DELETE")
students = make(map[int]Student)
students[1] = Student{1, "aaa", 16, 87}
students[2] = Student{2, "bbb", 18, 98}
lastId = 2
return mux
}
type Students []Student
func (s Students) Len() int {
return len(s)
}
func (s Students) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s Students) Less(i, j int) bool {
return s[i].Id < s[j].Id
}
func DeleteStudentHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, _ := strconv.Atoi(vars["id"])
_, ok := students[id]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
delete(students, id)
w.WriteHeader(http.StatusOK)
}
func PostStudentHandler(w http.ResponseWriter, r *http.Request) {
var student Student
err := json.NewDecoder(r.Body).Decode(&student)
fmt.Println(r.Body)
if err != nil {
fmt.Println("에러 발생!!")
w.WriteHeader(http.StatusBadRequest)
return
}
lastId++
student.Id = lastId
students[lastId] = student
w.WriteHeader(http.StatusCreated)
}
func GetStudentListHandler(w http.ResponseWriter, r *http.Request) {
list := make(Students, 0)
for _, student := range students {
fmt.Println(student)
list = append(list, student)
}
sort.Sort(list)
json.NewEncoder(w).Encode(list)
}
func GetStudentHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) //id값을 가져오는 방법
fmt.Println(vars)
id, _ := strconv.Atoi(vars["id"])
student, ok := students[id]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(student)
}
func main() {
http.ListenAndServe(":3000", MakeWebHandler())
}