상세 컨텐츠

본문 제목

[Nomad Coin] Explorer - #5.6 Recap

Go/Blockchain

by Gopythor 2022. 7. 18. 04:03

본문

728x90
반응형

#5.6 Recap

port        string = ":4000"

log.Fatal(http.ListenAndServe(port, nil))
  • Go에서 서버를 열기 위한 Listening과 Serving을 얼마나 쉽게 만들 수 있는지 배웠다. 위의 한 줄만 쓰면 된다.
  • port를 string으로 const 선언해서 넘겨주기만 하면 됐다.
  • 작업 중 발생하는 모든 에러를 보고 싶었다. Go는 에러를 보여주는 Exception들이 없기 때문에 직접 해야 한다.
  • 그걸 위해서 log.Fatal()을 썼다. 어떤 에러가 있든 console.log()해주고 os.Exit(1)로 프로그램을 panic 상태로 종료시킨다.
	http.HandleFunc("/", home)
	http.HandleFunc("/add", add)
  • 그 다음으로 배운건 URL처리하는 방식이다. JSON API에서도 방식은 같을 것이다.
  • http.HandelFunc()에 URL을 쓰고, function이 있다.
func home(rw http.ResponseWriter, r *http.Request) {
	data := homeData{"Home", blockchain.GetBlockchain().AllBlocks()}
	templates.ExecuteTemplate(rw, "home", data)
}

func add(rw http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		templates.ExecuteTemplate(rw, "add", nil)
	case "POST":
		r.ParseForm()
		data := r.Form.Get("blockData")
		blockchain.GetBlockchain().AddBlock(data)
		http.Redirect(rw, r, "/", http.StatusPermanentRedirect)
	}

}
  • handler라고 하는 이건 두개의 argument를 받는다.
  • 한개는 ResponseWriter이고, 나머지 하나는 Request의 포인터이다.
  • Write function은 HTTP응답의 일부로 연결에 데이터를 쓴다. 이게 우리가 사용자에게 대답하기 위해 HTTP 연결에 데이터를 쓸 수 있는 방법이다. 이런 이유로 Writer가 필요하다. 이걸로 사용자한테 대답 할 것이다.
  • 그리고 Request pointer가 필요하다. Request는 header, URL, method 등 모든 것을 알려준다. 전에 본 것처럼 Form도 있다. receiver function도 있다. 예를 들면 ParseForm()도 있다.
var templates *template.Template
  • templates Object는 여기 있는 variable이다.type은 Template struct의 pointer이다.

 

type homeData struct {
	PageTitle string
	Blocks    []*blockchain.Block
}
  • 다음으로 했던 건 user에게 보낼 데이터의 struct를 만든 것이다.
	templates = template.Must(template.ParseGlob(templateDir + "pages/*.gohtml"))
	templates = template.Must(templates.ParseGlob(templateDir + "partials/*.gohtml"))
  • 어떤 function이던지 handing하기 전에 여러 개의 template들을 loading했다. 이 모든 걸 templates variable에 넣었다.
  • 가장 먼저 했던 건 pages폴더 내부의 모든 gohtml파일 template들을 load한 것이다.
  • 그리고 거기에 partials 안에 있는 gohtml template 파일들을 또 다시 load 시켰다.
  • 정말 중요한데, 처음엔 standard library의 template를 사용했고, 그 다음엔 templates variable을 사용했다.
  • template위에 templates을 얹은 것이다.
  • ParseGlob funciton을 사용했는데, 이건 pattern을 사용해서 template을 load한다.
  • 그 전엔 ParseFiles()를 썼고, 그건 한번에 하나의 template을 파일 위치로 load 했다.
  • ParseGlob()경우는 이렇게 Pattern을 썼다. 그렇지만 **은 사용불가하여 두 줄로 코드를 한 것이다.
  • 또한 폴더 별로 파일 정리하는 것을 좋아해서 그렇게 된 것이다.
  • 한 폴더에 모든 파일을 가지고 있으면 한줄로도 정리가 가능하다.
  • 원한다면 모든 걸 한 폴더에 넣고 파일에 partial_footer.gohtml과 page_home.gohtml 과 같은 방식으로 쓸 수 있다.

 

  • template.Must()는 helper이다. Must가 하는 일은 에러가 있는지 확인하는 것 뿐이다.
  • Must()는 error에 대해서 우리가 확인하지 않아도 되도록 해준다.
  • helper function을 쓰기 때문에 에러 체크를 안해도 된다.
  • 추후에는 스스로 helper function을 만들 것이다.

 

func home(rw http.ResponseWriter, r *http.Request) {
	data := homeData{"Home", blockchain.GetBlockchain().AllBlocks()}
	templates.ExecuteTemplate(rw, "home", data)
}
  • ExecuteTemplate도 살펴봤었는데, 말 그대로의 작업을 해준다.
  • 이름이 'home'인 template을 실행시켜 줄 것이다.
  • response로 template를 실행시킬거니 ResponseWriter도 써주고 data도 전달했다.
  • Go에서 variable이나 object를 생성하거나 어딘가에서 가져와서 말 그대로 거기다가 데이터를 쓰게 된다.

  • 왜냐하면 데이터를 쓸 수 있을만큼 low-level에 있기 때문이다.
  • 나중엔 Byte buffer에 쓰는 방법도 알아볼 것이다.
{{define "home"}}
<!DOCTYPE html>
<html lang="en">
    {{template "head" .PageTitle}}
<body>
    {{template "header" .PageTitle}}
    <main>
        {{range .Blocks}} 
            {{template "block" .}}
        {{end}}
    </main>
    {{template "footer"}}
</body>
</html>
{{end}}
  • template에 Go 코드를 쓸 수 있다. 예를 들면 Array를 순회하기 위해서 range를 쓸 수 있다.
  • '.'는 사람들을 헷갈리게 할 수 있다. 이 점은 현재 가리키고 있는 데이터를 나타내는 커서이다.
  • 보이는 것처럼 가리키는게 달라 질 수 있다.
func home(rw http.ResponseWriter, r *http.Request) {
	data := homeData{"Home", blockchain.GetBlockchain().AllBlocks()}
	templates.ExecuteTemplate(rw, "home", data)
}
type homeData struct {
	PageTitle string
	Blocks    []*blockchain.Block
}
  • 예를 들면 home에는 data struct가 있었다.
  • PageTitle과 Blocks가 있다.
  • 즉 home.gohtml에서 '.' 이 점들은 보낸 데이터들을 가리킨다.
  • 지금 당장 저 점은 데이터를 가리키고 있고, .PageTitle x2, .Blocks라고 쓴 것이다.
        {{range .Blocks}} 
            {{template "block" .}}
        {{end}}
  • 하지만 range를 쓰게 되면 점이 가리키는게 달라지는데, 여기 있는 점은 template에 보내는 데이터가 아니라, Blocks 내부에 있는 Block을 가리키게 된다.
  • html 조각들을 어떻게 재사용하고 분리할 수 있는지도 배웠다.
  • 그냥 모든 곳에 {{define "template_name"}}을 해주면 됐다
  • block도 header도 모두 template을 만들고 이름을 붙여줬고, 당연히 데이터도 보낼 수 있다. home.gohtml에서 한 것 처럼.
  • Block template에 block struct 전체를 보내고 있다.
  • 이 코드에서 Blobk을 'block' template으로 보내고 있다는 걸 볼 수 있다.

 

{{define "block"}}
<div>
    <ul>
        <li><strong>Data: </strong>{{.Data}}</li>
        <li><strong>Hash: </strong>{{.Hash}}</li>
        {{if .PrevHash}}
            <li><strong>Previous Hash: </strong>{{.PrevHash}}</li>
        {{end}}
         </ul>
        </div>
    <hr />
{{end}}
  • block template로 가면 어떻게 쓰는 지 볼 수 있다.
  • 여기 있는 점은 template이 보내는 데이터가 아니라 Block struct라는 거를 기억한다.
  • 그래서 '.Data', '.Hash', '.PrevHash' 이렇게 쓸 수 있는 것이다.
  • if를 썼고 else도 할 수 있겠다. 
  • 마지막으로 {{end}}를 썼다.
 {{template "head" .PageTitle}}
  • templates에 이런 식으로 데이터를 보낼 수 있는 것도 기억해야 한다.
{{define "head"}}
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://unpkg.com/mvp.css">
    <title>{{.}} | 노마드 코인</title>
</head>
{{end}}
  • head로 PageTitle variable을 보내고 있는데, head에서 그 데이터를 보여주고 싶다면, .PageTitle이 아니라 '.'만 써주면 된다.
  • 왜냐하면 variable이 하나만 전달되기 때문이다. 딱 한개 있는 string data라서 할 수 있는 것이다.
func add(rw http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		templates.ExecuteTemplate(rw, "add", nil)
	case "POST":
		r.ParseForm()
		data := r.Form.Get("blockData")
		blockchain.GetBlockchain().AddBlock(data)
		http.Redirect(rw, r, "/", http.StatusPermanentRedirect)
	}

}
  • Add funciton은 정말 간단하다.
  • 'GET'이면 아무 데이터 없이 add template을 써준다.
  • data가 required argument지만 필요가 없어서 nil을 썼다.
  • 만약 'POST'라면, 가장 먼저 ParseForm()을 실행했다.
  • ParseForm()을 살펴보면 r.Form을 생성한다고 되어 있다.
  • r.Form은 map이다. 그리고 했던게 Values type을 확인하는 거였다. string과 string 조각들로 이루어진 map이다.
  • 그 후 receiver function을 써서 key로 가져올 수 있었다.
  • Form에서 데이터를 가져오기 위해 Form.Get()을 사용했다.
<main>
        <form method="POST" action="/add">
            <input type="text" placeholder="Data for your block" required name="blockData" />
            <button>Add Block</button>
        </form>
    </main>
  • 그리고 잊지말아야 할 것이 같은 이름을 사용해야 한다.
blockchain.GetBlockchain().AddBlock(data)
  • 그리고 전에 생성했던 함수를 호출했다.
http.Redirect(rw, r, "/", http.StatusPermanentRedirect)
  • 여기서 respond를 보내는게 아니라 http.Redirect()를 했다.
  • ResponseWriter를 쓴게 아니라 redirect하기 위해 Redirect를 사용한 것이다.
  • 여기엔 ResponseWriter가 필요하고, Request도 필요하고, 이동할 URL이 필요하고, 코드가 필요하다. 코드는 300이사이어야 하낟. 그게 redirect를 나타내는 코드이다.
  • 정확히 어떤 걸 써야 하는지 모르지만 Go가 우리를 위해 constant를 가지고 있고 StatusPermanentRedirect를 사용할 수 있다. 들어가면 모든 상태 코드를 확인해 볼 수 있다.
  • 그후 refactoring을 했다. refactoring를 했던 이유는 main.go를 정리하기 위해서였다. 나중에 JSON API 를 만들어야 해서 그랬다.

출처 : 노마드코더 노마드코인

728x90
반응형

관련글 더보기

댓글 영역