devops

Go로 간단한 블록체인 구현하기 - REST API 본문

DevOps/Chain

Go로 간단한 블록체인 구현하기 - REST API

vataops 2022. 12. 12. 23:09
반응형

REST API를 GO로 구현해서 blockchain부터 특정 block을 확인하고, 추가할 수 있도록 해본다.

package rest

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
)

var port string

type url string

func (u url) MarshalText() ([]byte, error) {
	url := fmt.Sprintf("http://localhost%s%s", port, u)
	return []byte(url), nil
}

type urlDescription struct {
	URL         url    `json:"url"`
	Method      string `json:"method"`
	Description string `json:"description"`
	Payload     string `json:"payload,omitempty"`
}

type addBlockBody struct {
	Message string
}

func documentation(rw http.ResponseWriter, r *http.Request) {
	data := []urlDescription{
		{
			URL:         url("/"),
			Method:      "GET",
			Description: "See Documentation",
		},
		{
			URL:         url("/blocks"),
			Method:      "GET",
			Description: "See All Blocks",
		},
		{
			URL:         url("/blocks"),
			Method:      "POST",
			Description: "Add A Block",
			Payload:     "data:string",
		},
		{
			URL:         url("/blocks/{height}"),
			Method:      "GET",
			Description: "See A Block",
		},
	}
	rw.Header().Add("Content-Type", "application/json")
	json.NewEncoder(rw).Encode(data)
}

func block(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, err := strconv.Atoi(vars["height"])
	utils.HandleErr(err)
	block := blockchain.GetBlockchain().GetBlock(id)

	json.NewEncoder(rw).Encode(block)
}

func blocks(rw http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		rw.Header().Add("Content-Type", "application/json")
		json.NewEncoder(rw).Encode(blockchain.GetBlockchain().AllBlocks())
	case "POST":
		var addBlockBody addBlockBody
		utils.HandleErr(json.NewDecoder(r.Body).Decode(&addBlockBody))
		blockchain.GetBlockchain().AddBlock(addBlockBody.Message)
		rw.WriteHeader(http.StatusCreated)
	}
}

func Start(aPort int) {
	router := mux.NewRouter()
	router.HandleFunc("/", documentation).Methods("GET")
	router.HandleFunc("/blocks", blocks).Methods("GET", "POST")
	router.HandleFunc("/blocks/{height:[0-9]+}", block).Methods("GET")

	// handler := http.NewServeMux()
	port = fmt.Sprintf(":%d", aPort)

	// handler.HandleFunc("/", documentation)
	// handler.HandleFunc("/blocks", blocks)

	fmt.Printf("Listening on http://localhost%s\n", port)
	log.Fatal(http.ListenAndServe(port, router))
}

gorilla/mux

GET, POST, PUT method를 효율적으로 구성하여 rest api를 구현하기 위해서 많이 사용하는 http router 패키지다. mux.NewRouter()를 통해서 라우터 함수를 등록하고 위 코드와 같이 마지막에 Methods() 함수를 붙여 필요한 method를 추가해준다.

https://github.com/gorilla/mux

 

GitHub - gorilla/mux: A powerful HTTP router and URL matcher for building Go web servers with 🦍

A powerful HTTP router and URL matcher for building Go web servers with 🦍 - GitHub - gorilla/mux: A powerful HTTP router and URL matcher for building Go web servers with 🦍

github.com


jsonContentTypeMiddleware

func jsonContentTypeMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		rw.Header().Add("Content-Type", "application/json")
		next.ServeHTTP(rw, r)
	})
}

헤더의 Content-Type에 application/json을 추가한 미들웨어를 생성하여 모든 json 응답에 포함시킨다.

반응형
Comments