
Tucker Go 언어 프로그래밍 예제를 통해 학습하였습니다.
http 패키지로만 구성되어 있는 예제를 Gin 패키지 이해도를 위해 모두 변경하여 만들어봤습니다.
// User Struct
type User struct {
	ID        int       `json:"id"`
	FirstName string    `json:"first_name"`
	LastName  string    `json:"last_name"`
	Email     string    `json:"email"`
	CreatedAt time.Time `json:"create_at"`
}







CRUD_gin - sub - sub.go
         - main.go
package main
import (
	"CRUD_gin/sub"
	"fmt"
	"net/http"
	"time"
	"golang.org/x/sync/errgroup"
)
var (
	g errgroup.Group
)
func main() {
	mapi := &http.Server{
		Addr:           ":8080",
		Handler:        sub.Index(),
		ReadTimeout:    5 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	g.Go(func() error {
		return mapi.ListenAndServe()
	})
	if err := g.Wait(); err != nil {
		fmt.Println(err)
	}
}
package sub
import (
	"fmt"
	"net/http"
	"strconv"
	"time"
	"github.com/gin-gonic/gin"
)
// in-memory로 관리하기 위함
var userMap map[int]*User
// id 처리를 위한 변수
var lastId int
// User Struct
type User struct {
	ID        int       `json:"id"`
	FirstName string    `json:"first_name"`
	LastName  string    `json:"last_name"`
	Email     string    `json:"email"`
	CreatedAt time.Time `json:"create_at"`
}
// cross domain을 위해 사용
func CORS() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		//허용할 header 타입에 대해 열거
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, X-Forwarded-For, Authorization, accept, origin, Cache-Control, X-Requested-With")
		//허용할 method에 대해 열거
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}
		c.Next()
	}
}
// GET : User 리스트 조회
func usersHandler(c *gin.Context) {
	// 만약 등록된 유저가 한명도 없을 경우
	if len(userMap) == 0 {
		if err := c.ShouldBindUri(&userMap); err != nil {
			fmt.Printf("error - %+v \n", err)
		}
		fmt.Printf("No User - %+v \n", userMap)
		return
	}
	// 등록된 유저가 있을 경우
	users := []*User{}
	for _, u := range userMap {
		users = append(users, u)
	}
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data":   users,
	})
}
// POST
func createUserHandler(c *gin.Context) {
	// 유저 객체를 저장하기 위한 구조체 선언
	user := new(User)
	if err := c.ShouldBindJSON(&user); err != nil {
		fmt.Printf("error - %+v \n", err)
		return
	}
	lastId++
	user.ID = lastId
	user.CreatedAt = time.Now()
	userMap[user.ID] = user
	c.JSON(http.StatusCreated, gin.H{
		"status": "ok",
		"data":   user,
	})
}
// PUT
func updateUserHandler(c *gin.Context) {
	// 클라이언트에서 받은 내용을 updataUser 구조체에 바인딩한다.
	updateUser := new(User)
	if err := c.ShouldBindJSON(&updateUser); err != nil {
		fmt.Printf("error - %+v \n", err)
		return
	}
	// 클라이언트에서 받은 ID값을 가진 유저가 기존 메모리에 등록되어 있는지 확인
	user, ok := userMap[updateUser.ID]
	if !ok {
		c.String(http.StatusOK, "No User ID : %d", updateUser.ID)
		return
	}
	// 업데이트된 항목만 변경
	if updateUser.FirstName != "" {
		user.FirstName = updateUser.FirstName
	}
	if updateUser.LastName != "" {
		user.LastName = updateUser.LastName
	}
	if updateUser.Email != "" {
		user.Email = updateUser.Email
	}
	// c.String(http.StatusOK, "user : %s", user)
	c.JSON(http.StatusCreated, gin.H{
		"status": "ok",
		"data":   user,
	})
}
func getUserHandler(c *gin.Context) {
	tempId := c.Param("id")
	id, err := strconv.Atoi(tempId)
	if err != nil {
		fmt.Printf("error - %+v \n", err)
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "This is not a valid value.",
		})
		return
	}
	user, ok := userMap[id]
	if !ok {
		c.JSON(http.StatusOK, gin.H{
			"status": "No User Id",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"user":   user,
	})
}
// DELETE
func deleteUserHandler(c *gin.Context) {
	// id, err := strconv.Atoi(tempId)
	tempId := c.Param("id")
	id, err := strconv.Atoi(tempId)
	if err != nil {
		fmt.Printf("error - %+v \n", err)
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "This is not a valid value.",
		})
		return
	}
	_, ok := userMap[id]
	if !ok {
		c.JSON(http.StatusOK, gin.H{
			"status": "No User Id",
		})
		return
	}
	delete(userMap, id)
	c.JSON(http.StatusOK, gin.H{
		"status": "Deleted User ",
		"id":     id,
	})
}
// GET
func Index() *gin.Engine {
	// in memory 사용
	userMap = make(map[int]*User)
	// user 마다 다른 아이디를 생성해주기 위한 변수
	lastId = 0
	// gin 인스턴스 생성
	router := gin.New()
	// logger 미들웨어 사용
	router.Use(gin.Logger())
	// Recovery 미들웨어 사용
	router.Use(gin.Recovery())
	// CORS 사용
	router.Use(CORS())
	router.GET("/users", usersHandler)
	router.POST("/users", createUserHandler)
	router.PUT("/users", updateUserHandler)
	router.DELETE("/users/:id", deleteUserHandler)
	router.GET("/users/:id", getUserHandler)
	return router
}