doujianwan7570 2016-12-23 15:30
浏览 32
已采纳

休息一下api服务器设计的好习惯

I am new to golang and would like to make a small web app of to-do list to polish my go skills. I would like to know what is a good practice to organize the code.

Right now, I define two packages for this project: ticket and server. ticket is about database and server is about http handlers.

My data has two types: Ticket and Todo. One Ticket can have multiple Todo in it. They are defined in the ticket package.

type Ticket struct {                                                               
    Id          int64      `db:"id" json:"id"`                                     
    Label       string     `db:"label" json:"label"`                               
    Description string     `db:"description" json:"description"`                   
    StartTime   time.Time  `db:"start_time" json:"start_time"`                     
    EndTime     *time.Time `db:"end_time" json:"end_time"`                         
    Priority    bool       `db:"priority" json:"priority"`                         
}                                                                                  
type Todo struct {                                                                 
    Id       int64 `db:"id" json:"id"`                                             
    Item     int64 `db:"item" json:"item"`                                         
    TicketId int64 `db:"ticket_id" json:"ticket_id"`                               
    Active   bool  `db:"active" json:"active"`                                     
}  

In the ticket package, I also define

type AppDB struct {                                                                
    db *sqlx.DB                                                                    
}   

This wrapping around *sqlx.DB allows me to put all the database access functions inside ticket package, e.g.,

func (adb *AppDB) MustInit() 
func (adb *AppDB) AddTicket(i *Ticket) (int64, error)

In the server package, I define

type Application struct {                                                          
    db ticket.AppDB                                                                
}   

And the http handler functions are defined as methods of Application, e.g.,

func (app *Application) CreateTicket(w http.ResponseWriter, req *http.Request)

In the main.go, I register the handle functions.

func main() {                                                                      
    app := server.NewApplication()                                                 

    fmt.Println("now listening...")                                                
    router := mux.NewRouter()                                                      
    router.HandleFunc("/", app.Hello).Methods("GET")                               
    router.HandleFunc("/get", app.Get).Methods("GET")                              
    log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), router))                  
}  

I have the following questions:

  1. Is this design a good practice? If not, what is the right way?
  2. In Donovan and Kernighan's Go programming book p.194, they give an example where the http handlers are defined as the database's method directly. Would that be a better design? It makes sense because my server package only works for data types in ticket. It also makes the code a little cleaner to write. On the other hand it mixes http and database, which I am not sure if it is a good thing.
  3. How to deal with database table creation? Shall I create another main.go which only creates the database tables and build it into executable such that I can run it on the server just once?
  • 写回答

1条回答 默认 最新

  • douleng3463 2016-12-29 09:50
    关注
    1. I think making 2 packages is a bad decision based on what you've described. If you're making a "small web app", there's nothing to gain but extra complexity in having more than one package. If you're not sure, always choose the simpler solution.

    2. I don't think having 2 packages is cleaner or that it mixes less. You can have your package stuff on several different files, and functions as methods of different structs.

    3. How about this? Define your db initialisation in an idempotent way (e.g. CREATE SCHEMA IF NOT EXISTS, CREATE TABLE IF NOT EXISTS) and run it every single time at the beginning of your main.go, right after you db.Ping(). Should be milliseconds most of the time, and you ensure that the db always has the structure you expect.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度