golang - gin demo解析

gin 初探

原文地址: https://ryanmccue.ca/creating-an-api-with-golang-gin-framework/

解析

总体结构

代码分解

  • main.go
package main

import (
"log"

"github.com/gin-gonic/gin"
"vincent.com/gin/todo/controllers"
"vincent.com/gin/todo/routes"
"vincent.com/gin/todo/utils/database"
)

func main() {
// 链接db 获取实例
db, err := database.Connect("postgres", "", "postgres", "192.168.33.10", "5432")
if err != nil {
log.Fatal("err", err)
}
// binding db 和 controller
todoController := controllers.NewTodoController(db)
// 默认配置
r := gin.Default()
// 路由注册
routes.CreateRoutes(r, todoController)
// 默认8080端口
r.Run()
}
  • database.go
    数据链接函数
package database

import (
"database/sql"
"fmt"
// import pg
_ "github.com/lib/pq"
)

// Connect function for pgsql
func Connect(user, password, dbname, host, port string) (*sql.DB, error) {
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%s sslmode=disable",
user, password, dbname, host, port)
return sql.Open("postgres", connStr)
}
  • items.go 数据模型
package models

// Item - todo item model
type Item struct {
ID int `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Completed bool `json:"status"`
}
  • todo_controller.go 参数/error/调用 actions
package controllers

import (
"database/sql"
"log"
"net/http"
"strconv"

"github.com/gin-gonic/gin"
"vincent.com/gin/todo/repositories"
)

//NewTodoController - create todo controller with mehtod dealing with todo item
func NewTodoController(db *sql.DB) *TodoController {
return &TodoController{DB: db}
}

//TodoController struct
type TodoController struct {
DB *sql.DB
}

//Create - get req and create one todo item into pg
func (tc *TodoController) Create(c *gin.Context) {
// 解析参数
title := c.PostForm("title")
description := c.PostForm("description")
// 调用 sql层
_, err := repositories.CreateItem(tc.DB, title, description)
// 错误处理
if err != nil {
log.Println("err", err)
c.String(http.StatusInternalServerError, "")
return
}
c.String(http.StatusCreated, "")
}

//Items - query todo items from pg
func (tc *TodoController) Items(c *gin.Context) {
allStr := c.Query("all")
all, err := strconv.ParseBool(allStr)
if err != nil {
all = true
}
items, err := repositories.GetItems(tc.DB, all)
if err != nil {
log.Println("err", err)
c.String(http.StatusInternalServerError, "")
return
}
c.JSON(http.StatusOK, items)
}

//Get - get one item with id
func (tc *TodoController) Get(c *gin.Context) {
itemIDStr := c.Params.ByName("itemID")
itemID, err := strconv.Atoi(itemIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, map[string]string{
"error": "Bad item id",
})
return
}
item, err := repositories.GetItem(tc.DB, itemID)
if err != nil {
if err == sql.ErrNoRows {
c.String(http.StatusNotFound, "")
return
}
log.Println("err", err)
c.String(http.StatusInternalServerError, "")
return
}
c.JSON(http.StatusOK, item)
}

//Update - update item with id
func (tc *TodoController) Update(c *gin.Context) {
itemIDStr := c.Params.ByName("itemID")
itemID, err := strconv.Atoi(itemIDStr)
if err != nil {
log.Println("err", err)
c.JSON(http.StatusBadRequest, map[string]string{
"error": "Bad item id",
})
return
}
title := c.PostForm("title")
description := c.PostForm("description")
completedStr := c.PostForm("completed")
completed, err := strconv.ParseBool(completedStr)
if err != nil {
c.JSON(http.StatusBadRequest, map[string]string{
"error": "Bad completed input",
})
return
}
err = repositories.UpdateItem(tc.DB, itemID, title, description, completed)
if err != nil {
log.Println("err", err)
c.String(http.StatusInternalServerError, "")
return
}
c.String(http.StatusOK, "")
}

//Delete - del item with id
func (tc *TodoController) Delete(c *gin.Context) {
itemIDStr := c.Param("itemID")
itemID, err := strconv.Atoi(itemIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, map[string]string{
"error": "Bad item id",
})
return
}
err = repositories.DeleteItem(tc.DB, itemID)
if err != nil {
log.Println("err", err)
c.String(http.StatusInternalServerError, "")
return
}
c.String(http.StatusOK, "")
}
  • routes.go 关联  路由和 controller

    此  例子没有分组

package routes

import (
"github.com/gin-gonic/gin"
"vincent.com/gin/todo/controllers"
)

//CreateRoutes - bind controller with gin
func CreateRoutes(r *gin.Engine, tc *controllers.TodoController) {
r.GET("/items", tc.Items)
r.POST("/item", tc.Create)
r.GET("/item/:itemID", tc.Get)
r.PUT("/item/:itemID", tc.Update)
r.DELETE("/item/:itemID", tc.Delete)
}
  • todo_repository.go 操作 db
package repositories

import (
"database/sql"

"vincent.com/gin/todo/models"
)

//GetItems - get items from pg
func GetItems(db *sql.DB, all bool) ([]*models.Item, error) {
var rows *sql.Rows
var err error
query := `
select
id,
title,
description,
completed
from
items
`
if !all {
query += "where completed = $1"
rows, err = db.Query(query, all)
} else {
rows, err = db.Query(query)
}

if err != nil {
return nil, err
}
items := make([]*models.Item, 0)

for rows.Next() {
var item models.Item
err = rows.Scan(&item.ID, &item.Title, &item.Description, &item.Completed)
if err != nil {
return nil, err
}
items = append(items, &item)
}
return items, err
}

//CreateItem - add new todo item
func CreateItem(db *sql.DB, title, description string) (int, error) {
const query = `
insert into items (
title,
description
) values (
$1,
$2
) returning id
`
var id int
err := db.QueryRow(query, title, description).Scan(&id)
return id, err
}

//UpdateItem - update item base on id
func UpdateItem(db *sql.DB, id int, title, description string, completed bool) error {
const query = `
update items set
title = $1,
description = $2,
completed = $3
where id = $4
`
_, err := db.Exec(query, title, description, completed, id)
return err
}

//GetItem - get item with specific id
func GetItem(db *sql.DB, id int) (*models.Item, error) {
const query = `
select
id,
title,
description,
completed
from
items
where
id = $1
`
var item models.Item
err := db.QueryRow(query, id).Scan(&item.ID, &item.Title, &item.Description, &item.Completed)
return &item, err
}

//DeleteItem - del the todo item with specific id
func DeleteItem(db *sql.DB, id int) error {
const query = `delete from items where id = $1`
_, err := db.Exec(query, id)
return err
}