Golang - 웹 서버 - 2

Lumi·2022년 2월 17일
0

Golang

목록 보기
28/38
post-thumbnail

🔥 RESTful API

웹 서버를 구축할떄의 기준점이라고 할수 있는 RESTful API를 활용한 서버를 공부하였습니다.

대부분 HTTP메서드를 다루는 방법에 대해서 학습이 진행되었습니다.

  • RESTful API에 대한 정의가 뚜렷하지 않아서;;

🔨 RESTful API 서버 만들기

일단 기본적으로 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메서드를 지정해 줍니다.

  • 이런 방식이면 해당 경로의 GET요청은 뒤에 따라오는 함수가 작동한다는 의미가 됩니다.

이후 데이터 값들을 입력해 줌으로써 준비가 끝납니다.

이 부분의 작동 방식에 대해서는 Youtube를 통해서 다루어 보겠습니다.

🔨 특정 데이터 반환하기 [Mux.vars]

이제 특정 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]

드디어 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요청이기 떄문에 들어오는 데이터를 담고 이후 변수값에 추가해 주는 방법으로 작동을 하게 됩니다.

🔨 데이터 삭제 [Delete]

그럼 반대로 삭제하는 방법에 대해서 다루어 보겠습니다.

먼저 핸들러를 추가해 줍니다.

  • 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())
}

코드에 대한 실습 및 작동 원리는 Youtube에 정리 하였습니다!

profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글