https://www.youtube.com/watch?v=TjbUnpW7wyA
- net/http 의 NewServeMux를 사용한 웹서버 구축
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func getUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket", Email: "tucket@naver.com"}
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/users", getUserInfoHandler)
http.ListenAndServe(":8000", mux)
}
- gorilla/mux를 사용한 웹서버 구축
- main 소스를 보면 mux.NewRouter()를 통하여 gorilla/mux를 사용한다. 위의 소스와 달리 같은 경로인데 Get,Post로 구분하였다.
func main() {
mux := mux.NewRouter()
mux.HandleFunc("/users", getUserInfoHandler).Methods("GET")
mux.HandleFunc("/users", postUserInfoHandler).Methods("POST")
http.ListenAndServe(":8000", mux)
}
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/mux"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func getUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket", Email: "tucket@naver.com"}
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
func postUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket", Email: "tucket@naver.com"}
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
func main() {
mux := mux.NewRouter()
mux.HandleFunc("/users", getUserInfoHandler).Methods("GET")
mux.HandleFunc("/users", postUserInfoHandler).Methods("POST")
http.ListenAndServe(":8000", mux)
}
- gorilla/pat를 설치한다.
go get github.com/gorilla/pat
- gorilla/pat을 사용하면 아래와 같이 main()쪽만 수정하면된다. 아래와 같이 좀더 간단하게 표시가능하다.
func main() {
mux := pat.New()
mux.Get("/users", getUserInfoHandler)
mux.Post("/users", postUserInfoHandler)
http.ListenAndServe(":8000", mux)
}
- 아래는 gorilla/pat 의 전체 코드이다.
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/pat"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func getUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket_pat_get", Email: "tucket@naver.com"}
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
func postUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket_pat_post", Email: "tucket@naver.com"}
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
func main() {
mux := pat.New()
mux.Get("/users", getUserInfoHandler)
mux.Post("/users", postUserInfoHandler)
http.ListenAndServe(":8000", mux)
}
- 위의 gorilla/pat 의 코드를 좀더 수정해보자
- User 구조체에 CreatedAt을 추가하였다.
type User struct {
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
- postUserInfoHandler 함수를 아래와 같이 변경하였다. Post전송시 입력은 json데이타를 보내야한다.
func postUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := new(User)
err := json.NewDecoder(r.Body).Decode(user)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprint(w, err)
return
}
user.CreatedAt = time.Now()
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
- getHelloHandler 함수를 추가하였다. 해당 함수는 hello.tmpl파일을 사용한다.
func getHelloHandler(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.New("Hello").ParseFiles("templates/hello.tmpl")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, err)
return
}
tmpl.ExecuteTemplate(w, "hello.tmpl", "Tucker")
}
- 아래는 풀소스이다.
package main
import (
"encoding/json"
"fmt"
"html/template"
"net/http"
"time"
"github.com/gorilla/pat"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func getUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket_pat_get", Email: "tucket@naver.com"}
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
func postUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := new(User)
err := json.NewDecoder(r.Body).Decode(user)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprint(w, err)
return
}
user.CreatedAt = time.Now()
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
}
func getHelloHandler(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.New("Hello").ParseFiles("templates/hello.tmpl")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, err)
return
}
tmpl.ExecuteTemplate(w, "hello.tmpl", "Tucker")
}
func main() {
mux := pat.New()
mux.Get("/users", getUserInfoHandler)
mux.Post("/users", postUserInfoHandler)
mux.Get("/hello", getHelloHandler)
http.ListenAndServe(":8000", mux)
}
- templates폴더의 hello.tmpl
<html>
<head>
<title>Hello Go in Web</title>
</head>
<body>
Hello World {{.}}
</body>
</html>
- REST api 를 하나 만들때마다 작업하는 코드가 많다. 해당 작업을 편하게 하기 위해서 render를 사용해보자
- 일단 해당 패키지를 설치하자.
go get github.com/unrolled/render
아래의 코드를 ,
w.Header().Add("Content-type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprintf(w, string(data))
이렇게 한줄로 처리할수있다.
rd.JSON(w, http.StatusOK, user)
- render를 사용하면 아래처럼 코드를 정말 간단하게 처리할수있다.
- 위의 소스와 비교해보면 상당히 많이 코드가 줄었다.
package main
import (
"encoding/json"
"net/http"
"time"
"github.com/gorilla/pat"
"github.com/unrolled/render"
)
var rd *render.Render
type User struct {
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func getUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket_pat_get", Email: "tucket@naver.com"}
rd.JSON(w, http.StatusOK, user)
}
func postUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := new(User)
err := json.NewDecoder(r.Body).Decode(user)
if err != nil {
rd.Text(w, http.StatusBadRequest, err.Error())
return
}
user.CreatedAt = time.Now()
rd.JSON(w, http.StatusOK, user)
}
func getHelloHandler(w http.ResponseWriter, r *http.Request) {
rd.HTML(w, http.StatusOK, "hello", "Tucker")
}
func main() {
rd = render.New()
mux := pat.New()
mux.Get("/users", getUserInfoHandler)
mux.Post("/users", postUserInfoHandler)
mux.Get("/hello", getHelloHandler)
http.ListenAndServe(":8000", mux)
}
- 만약에 폴더가 templates가 아니고 template이고, hello.tmpl 대신에 hello.html를 사용하려고 하면, 아래와 같이 rd를 수정하면 된다.
rd = render.New(render.Options{
Directory: "template",
Extensions: []string{".html", ".tmpl"},
})
- hello는 레이아웃이라 body로 이름을 바꾼다. 문자열 대신에 user객체를 보내서 Name,Email을 사용한다.
func getHelloHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket_hello_get", Email: "tucket@naver.com"}
rd.HTML(w, http.StatusOK, "body", user)
}
- render.New()에서 기본 Layout을 지정한다.
rd = render.New(render.Options{
Directory: "template",
Extensions: []string{".html", ".tmpl"},
Layout: "hello",
})
- body.html이다.
Name: {{.Name}}
Email: {{.Email}}
- hello.html이다.
<html>
<head>
<title>{{ partial "title" }}</title>
</head>
<body>
Hello World
{{ yield }}
</body>
</html>
- 아래는 전체 소스이다.
package main
import (
"encoding/json"
"net/http"
"time"
"github.com/gorilla/pat"
"github.com/unrolled/render"
)
var rd *render.Render
type User struct {
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func getUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket_pat_get", Email: "tucket@naver.com"}
rd.JSON(w, http.StatusOK, user)
}
func postUserInfoHandler(w http.ResponseWriter, r *http.Request) {
user := new(User)
err := json.NewDecoder(r.Body).Decode(user)
if err != nil {
rd.Text(w, http.StatusBadRequest, err.Error())
return
}
user.CreatedAt = time.Now()
rd.JSON(w, http.StatusOK, user)
}
func getHelloHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "tucket_hello_get", Email: "tucket@naver.com"}
rd.HTML(w, http.StatusOK, "body", user)
}
func main() {
rd = render.New(render.Options{
Directory: "template",
Extensions: []string{".html", ".tmpl"},
Layout: "hello",
})
mux := pat.New()
mux.Get("/users", getUserInfoHandler)
mux.Post("/users", postUserInfoHandler)
mux.Get("/hello", getHelloHandler)
http.ListenAndServe(":8000", mux)
}
- title-body.html을 생성하여 아래와 같이 내용을 넣는다.
Partial Go in Web
- hello.html의 {{ partial "title" }} 부분에서 해당 title-body.html을 사용하여 아래와 같은 결과가 나온다.
- main() 함수에 mux.Handle("/", http.FileServer((http.Dir("public")))) 를 추가하고,
- public/index.html에 아래의 내용을 넣어서 실행해보자.
<html>
<head>
<title>Go in Web 11</title>
</head>
<body>
<h1>Hello Go in Web</h1>
</body>
</html>
Negroni 패키지
- main()에서 mux.Handle("/", http.FileServer((http.Dir("public")))) 를 삭제하고 아래와 같이 변경한다.
- 해당 파일을 실행하면 위와 결과가 같음을 알수있다.
- negroni에서 파일서버의 기능을 기본으로 지원하기 때문이다.
n := negroni.Classic()
n.UseHandler(mux)
http.ListenAndServe(":8000", n)
'Go' 카테고리의 다른 글
Go 채팅서버 (0) | 2024.03.30 |
---|---|
[묘공단] Tucker의 Go 언어 프로그래밍 31장 : Todo 리스트 웹사이트 만들기 (0) | 2024.03.24 |
[묘공단] Tucker의 Go 언어 프로그래밍 30장 : RESTful API 서버 만들기 (0) | 2024.03.22 |
[묘공단] Tucker의 Go 언어 프로그래밍 29장 : Go언어로 만드는 웹서버 (0) | 2024.03.16 |
[묘공단] Tucker의 Go 언어 프로그래밍 26장 : 단어검색프로그램 (0) | 2024.03.09 |