├── app.go ├── .gitignore ├── models ├── user.go ├── movies.go └── db.go ├── helper └── utils.go ├── LICENSE ├── routes └── routes.go ├── auth └── middleware.go ├── controllers ├── user.go └── movies.go └── README.md /app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/coderminer/restful/routes" 7 | ) 8 | 9 | func main() { 10 | r := routes.NewRouter() 11 | 12 | http.ListenAndServe(":8080", r) 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | -------------------------------------------------------------------------------- /models/user.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type User struct { 4 | UserName string `bson:"username" json:"username"` 5 | Password string `bson:"password" json:"password"` 6 | } 7 | 8 | type JwtToken struct { 9 | Token string `json:"token"` 10 | } 11 | -------------------------------------------------------------------------------- /helper/utils.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | ) 7 | 8 | type Response struct { 9 | Code int `json:"code"` 10 | Msg string `json:"msg"` 11 | Data interface{} `json:"data"` 12 | } 13 | 14 | func ResponseWithJson(w http.ResponseWriter, code int, payload interface{}) { 15 | response, _ := json.Marshal(payload) 16 | w.Header().Set("Content-Type", "application/json") 17 | w.WriteHeader(code) 18 | w.Write(response) 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CoderMiner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /models/movies.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "github.com/globalsign/mgo/bson" 4 | 5 | type Movies struct { 6 | Id bson.ObjectId `bson:"_id" json:"id"` 7 | Name string `bson:"name" json:"name"` 8 | CoverImage string `bson:"cover_image" json:"cover_image"` 9 | Description string `bson:"description" json:"description"` 10 | } 11 | 12 | const ( 13 | db = "Movies" 14 | collection = "MovieModel" 15 | ) 16 | 17 | func (m *Movies) InsertMovie(movie Movies) error { 18 | return Insert(db, collection, movie) 19 | } 20 | 21 | func (m *Movies) FindAllMovies() ([]Movies, error) { 22 | var result []Movies 23 | err := FindAll(db, collection, nil, nil, &result) 24 | return result, err 25 | } 26 | 27 | func (m *Movies) FindMovieById(id string) (Movies, error) { 28 | var result Movies 29 | err := FindOne(db, collection, bson.M{"_id": bson.ObjectIdHex(id)}, nil, &result) 30 | return result, err 31 | } 32 | 33 | func (m *Movies) UpdateMovie(movie Movies) error { 34 | return Update(db, collection, bson.M{"_id": movie.Id}, movie) 35 | } 36 | 37 | func (m *Movies) RemoveMovie(id string) error { 38 | return Remove(db, collection, bson.M{"_id": bson.ObjectIdHex(id)}) 39 | } 40 | -------------------------------------------------------------------------------- /routes/routes.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/coderminer/restful/auth" 7 | "github.com/coderminer/restful/controllers" 8 | "github.com/gorilla/mux" 9 | ) 10 | 11 | type Route struct { 12 | Method string 13 | Pattern string 14 | Handler http.HandlerFunc 15 | Middleware mux.MiddlewareFunc 16 | } 17 | 18 | var routes []Route 19 | 20 | func init() { 21 | register("GET", "/movies", controllers.AllMovies, auth.TokenMiddleware) 22 | register("GET", "/movies/{id}", controllers.FindMovie, nil) 23 | register("POST", "/movies", controllers.CreateMovie, nil) 24 | register("PUT", "/movies", controllers.UpdateMovie, nil) 25 | register("DELETE", "/movies/{id}", controllers.DeleteMovie, nil) 26 | 27 | register("POST", "/user/register", controllers.Register, nil) 28 | register("POST", "/user/login", controllers.Login, nil) 29 | } 30 | 31 | func NewRouter() *mux.Router { 32 | router := mux.NewRouter() 33 | for _, route := range routes { 34 | r := router.Methods(route.Method). 35 | Path(route.Pattern) 36 | if route.Middleware != nil { 37 | r.Handler(route.Middleware(route.Handler)) 38 | } else { 39 | r.Handler(route.Handler) 40 | } 41 | } 42 | return router 43 | } 44 | 45 | func register(method, pattern string, handler http.HandlerFunc, middleware mux.MiddlewareFunc) { 46 | routes = append(routes, Route{method, pattern, handler, middleware}) 47 | } 48 | -------------------------------------------------------------------------------- /auth/middleware.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/coderminer/restful/helper" 8 | "github.com/coderminer/restful/models" 9 | jwt "github.com/dgrijalva/jwt-go" 10 | ) 11 | 12 | func GenerateToken(user *models.User) (string, error) { 13 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ 14 | "username": user.UserName, 15 | //"exp": time.Now().Add(time.Hour * 2).Unix(), 16 | }) 17 | 18 | return token.SignedString([]byte("secret")) 19 | } 20 | 21 | func TokenMiddleware(next http.Handler) http.Handler { 22 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 23 | tokenStr := r.Header.Get("authorization") 24 | if tokenStr == "" { 25 | helper.ResponseWithJson(w, http.StatusUnauthorized, 26 | helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"}) 27 | } else { 28 | token, _ := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { 29 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 30 | helper.ResponseWithJson(w, http.StatusUnauthorized, 31 | helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"}) 32 | return nil, fmt.Errorf("not authorization") 33 | } 34 | return []byte("secret"), nil 35 | }) 36 | if !token.Valid { 37 | helper.ResponseWithJson(w, http.StatusUnauthorized, 38 | helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"}) 39 | } else { 40 | next.ServeHTTP(w, r) 41 | } 42 | } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /controllers/user.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/coderminer/restful/auth" 8 | "github.com/coderminer/restful/helper" 9 | "github.com/coderminer/restful/models" 10 | "github.com/globalsign/mgo/bson" 11 | ) 12 | 13 | const ( 14 | db = "Movies" 15 | collection = "UserModel" 16 | ) 17 | 18 | func Register(w http.ResponseWriter, r *http.Request) { 19 | var user models.User 20 | err := json.NewDecoder(r.Body).Decode(&user) 21 | if err != nil || user.UserName == "" || user.Password == "" { 22 | helper.ResponseWithJson(w, http.StatusBadRequest, 23 | helper.Response{Code: http.StatusBadRequest, Msg: "bad params"}) 24 | return 25 | } 26 | err = models.Insert(db, collection, user) 27 | if err != nil { 28 | helper.ResponseWithJson(w, http.StatusInternalServerError, 29 | helper.Response{Code: http.StatusInternalServerError, Msg: "internal error"}) 30 | } 31 | } 32 | 33 | func Login(w http.ResponseWriter, r *http.Request) { 34 | var user models.User 35 | err := json.NewDecoder(r.Body).Decode(&user) 36 | if err != nil { 37 | helper.ResponseWithJson(w, http.StatusBadRequest, 38 | helper.Response{Code: http.StatusBadRequest, Msg: "bad params"}) 39 | } 40 | exist := models.IsExist(db, collection, bson.M{"username": user.UserName}) 41 | if exist { 42 | token, _ := auth.GenerateToken(&user) 43 | helper.ResponseWithJson(w, http.StatusOK, 44 | helper.Response{Code: http.StatusOK, Data: models.JwtToken{Token: token}}) 45 | } else { 46 | helper.ResponseWithJson(w, http.StatusNotFound, 47 | helper.Response{Code: http.StatusNotFound, Msg: "the user not exist"}) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /models/db.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/globalsign/mgo" 7 | ) 8 | 9 | const ( 10 | host = "127.0.0.1:27017" 11 | source = "admin" 12 | user = "user" 13 | pass = "123456" 14 | ) 15 | 16 | var globalS *mgo.Session 17 | 18 | func init() { 19 | dialInfo := &mgo.DialInfo{ 20 | Addrs: []string{host}, 21 | Source: source, 22 | Username: user, 23 | Password: pass, 24 | } 25 | s, err := mgo.DialWithInfo(dialInfo) 26 | if err != nil { 27 | log.Fatalln("create session error ", err) 28 | } 29 | globalS = s 30 | } 31 | 32 | func connect(db, collection string) (*mgo.Session, *mgo.Collection) { 33 | s := globalS.Copy() 34 | c := s.DB(db).C(collection) 35 | return s, c 36 | } 37 | 38 | func Insert(db, collection string, docs ...interface{}) error { 39 | ms, c := connect(db, collection) 40 | defer ms.Close() 41 | return c.Insert(docs...) 42 | } 43 | 44 | func IsExist(db, collection string, query interface{}) bool { 45 | ms, c := connect(db, collection) 46 | defer ms.Close() 47 | count, _ := c.Find(query).Count() 48 | return count > 0 49 | } 50 | 51 | func FindOne(db, collection string, query, selector, result interface{}) error { 52 | ms, c := connect(db, collection) 53 | defer ms.Close() 54 | return c.Find(query).Select(selector).One(result) 55 | } 56 | 57 | func FindAll(db, collection string, query, selector, result interface{}) error { 58 | ms, c := connect(db, collection) 59 | defer ms.Close() 60 | return c.Find(query).Select(selector).All(result) 61 | } 62 | 63 | func Update(db, collection string, query, update interface{}) error { 64 | ms, c := connect(db, collection) 65 | defer ms.Close() 66 | return c.Update(query, update) 67 | } 68 | 69 | func Remove(db, collection string, query interface{}) error { 70 | ms, c := connect(db, collection) 71 | defer ms.Close() 72 | return c.Remove(query) 73 | } 74 | -------------------------------------------------------------------------------- /controllers/movies.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/coderminer/restful/models" 8 | "github.com/globalsign/mgo/bson" 9 | "github.com/gorilla/mux" 10 | ) 11 | 12 | var ( 13 | dao = models.Movies{} 14 | ) 15 | 16 | func responseWithJson(w http.ResponseWriter, code int, payload interface{}) { 17 | response, _ := json.Marshal(payload) 18 | w.Header().Set("Content-Type", "application/json") 19 | w.WriteHeader(code) 20 | w.Write(response) 21 | } 22 | 23 | func AllMovies(w http.ResponseWriter, r *http.Request) { 24 | defer r.Body.Close() 25 | var movies []models.Movies 26 | movies, err := dao.FindAllMovies() 27 | if err != nil { 28 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 29 | return 30 | } 31 | responseWithJson(w, http.StatusOK, movies) 32 | 33 | } 34 | 35 | func FindMovie(w http.ResponseWriter, r *http.Request) { 36 | vars := mux.Vars(r) 37 | id := vars["id"] 38 | result, err := dao.FindMovieById(id) 39 | if err != nil { 40 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 41 | return 42 | } 43 | responseWithJson(w, http.StatusOK, result) 44 | } 45 | 46 | func CreateMovie(w http.ResponseWriter, r *http.Request) { 47 | defer r.Body.Close() 48 | var movie models.Movies 49 | if err := json.NewDecoder(r.Body).Decode(&movie); err != nil { 50 | responseWithJson(w, http.StatusBadRequest, "Invalid request payload") 51 | return 52 | } 53 | movie.Id = bson.NewObjectId() 54 | if err := dao.InsertMovie(movie); err != nil { 55 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 56 | return 57 | } 58 | responseWithJson(w, http.StatusCreated, movie) 59 | } 60 | 61 | func UpdateMovie(w http.ResponseWriter, r *http.Request) { 62 | defer r.Body.Close() 63 | var params models.Movies 64 | if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { 65 | responseWithJson(w, http.StatusBadRequest, "Invalid request payload") 66 | return 67 | } 68 | if err := dao.UpdateMovie(params); err != nil { 69 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 70 | return 71 | } 72 | responseWithJson(w, http.StatusOK, map[string]string{"result": "success"}) 73 | } 74 | 75 | func DeleteMovie(w http.ResponseWriter, r *http.Request) { 76 | vars := mux.Vars(r) 77 | id := vars["id"] 78 | if err := dao.RemoveMovie(id); err != nil { 79 | responseWithJson(w, http.StatusBadRequest, "Invalid request payload") 80 | return 81 | } 82 | 83 | responseWithJson(w, http.StatusOK, map[string]string{"result": "success"}) 84 | } 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 使用Golang和MongoDB构建 RESTful API 2 | 3 | 记录一下创建 **RESTful API**使用 `Go`开发语言和 `MongoDB`后台数据库 4 | 5 | [完整代码 Github](https://github.com/coderminer/restful) 6 | 7 | ![](http://7xplrz.com1.z0.glb.clouddn.com//corderminer/website/golang_restful_api.png) 8 | 9 | #### 安装依赖 10 | 11 | ``` 12 | go get github.com/globalsign/mgo // MongoDB的Go语言驱动 13 | go get github.com/gorilla/mux // Go语言的http路由库 14 | ``` 15 | 16 | #### API 结构预览 17 | 18 | `app.go` 19 | 20 | ``` 21 | package main 22 | 23 | import ( 24 | "fmt" 25 | "net/http" 26 | 27 | "github.com/gorilla/mux" 28 | ) 29 | 30 | func AllMovies(w http.ResponseWriter, r *http.Request) { 31 | fmt.Fprintln(w, "not implemented !") 32 | } 33 | 34 | func FindMovie(w http.ResponseWriter, r *http.Request) { 35 | fmt.Fprintln(w, "not implemented !") 36 | } 37 | 38 | func CreateMovie(w http.ResponseWriter, r *http.Request) { 39 | fmt.Fprintln(w, "not implemented !") 40 | } 41 | 42 | func UpdateMovie(w http.ResponseWriter, r *http.Request) { 43 | fmt.Fprintln(w, "not implemented !") 44 | } 45 | 46 | func DeleteMovie(w http.ResponseWriter, r *http.Request) { 47 | fmt.Fprintln(w, "not implemented !") 48 | } 49 | 50 | func main() { 51 | r := mux.NewRouter() 52 | 53 | r.HandleFunc("/movies", AllMovies).Methods("GET") 54 | r.HandleFunc("/movies/{id}", FindMovie).Methods("GET") 55 | r.HandleFunc("/movies", CreateMovie).Methods("POST") 56 | r.HandleFunc("/movies", UpdateMovie).Methods("PUT") 57 | r.HandleFunc("/movies", DeleteMovie).Methods("DELETE") 58 | 59 | http.ListenAndServe(":8080", r) 60 | } 61 | 62 | ``` 63 | 64 | 随着后续路由的增加,需要重构一个这个文件,仿照 `beego`的工程目录,我们也分别创建对应的 `controllers` 65 | 和 `routes`,改造一下上面的代码 66 | 67 | * 控制器 68 | 69 | 创建 `controllers` 文件夹和对应的文件 `movies.go` 70 | 71 | `movies.go` 72 | 73 | ``` 74 | func AllMovies(w http.ResponseWriter, r *http.Request) { 75 | fmt.Fprintln(w, "not implemented !") 76 | } 77 | 78 | func FindMovie(w http.ResponseWriter, r *http.Request) { 79 | fmt.Fprintln(w, "not implemented !") 80 | } 81 | 82 | func CreateMovie(w http.ResponseWriter, t *http.Request) { 83 | fmt.Fprintln(w, "not implemented !") 84 | } 85 | 86 | func UpdateMovie(w http.ResponseWriter, r *http.Request) { 87 | fmt.Fprintln(w, "not implemented !") 88 | } 89 | 90 | func DeleteMovie(w http.ResponseWriter, r *http.Request) { 91 | fmt.Fprintln(w, "not implemented !") 92 | } 93 | ``` 94 | 95 | * 路由 96 | 97 | 创建一个 `routes`文件夹,并创建对应的文件 `routes.go` 98 | 99 | `routes.go` 100 | 101 | ``` 102 | package routes 103 | 104 | import ( 105 | "net/http" 106 | 107 | "github.com/coderminer/restful/controllers" 108 | "github.com/gorilla/mux" 109 | ) 110 | 111 | type Route struct { 112 | Method string 113 | Pattern string 114 | Handler http.HandlerFunc 115 | Middleware mux.MiddlewareFunc 116 | } 117 | 118 | var routes []Route 119 | 120 | func init() { 121 | register("GET", "/movies", controllers.AllMovies, nil) 122 | register("GET", "/movies/{id}", controllers.FindMovie, nil) 123 | register("POST", "/movies", controllers.CreateMovie, nil) 124 | register("PUT", "/movies", controllers.UpdateMovie, nil) 125 | register("DELETE", "/movies", controllers.DeleteMovie, nil) 126 | } 127 | 128 | func NewRouter() *mux.Router { 129 | r := mux.NewRouter() 130 | for _, route := range routes { 131 | r.Methods(route.Method). 132 | Path(route.Pattern). 133 | Handler(route.Handler) 134 | if route.Middleware != nil { 135 | r.Use(route.Middleware) 136 | } 137 | } 138 | return r 139 | } 140 | 141 | func register(method, pattern string, handler http.HandlerFunc, middleware mux.MiddlewareFunc) { 142 | routes = append(routes, Route{method, pattern, handler, middleware}) 143 | } 144 | 145 | ``` 146 | 147 | 重构后的 `app.go` 148 | 149 | ``` 150 | package main 151 | 152 | import ( 153 | "net/http" 154 | 155 | "github.com/coderminer/restful/routes" 156 | ) 157 | 158 | func main() { 159 | r := routes.NewRouter() 160 | 161 | http.ListenAndServe(":8080", r) 162 | } 163 | ``` 164 | 165 | #### Models 166 | 167 | * 创建 `models` 文件夹和对应的文件 `db.go`(数据层),封装对`MongoDB`的封装 168 | 169 | ``` 170 | package models 171 | 172 | import ( 173 | "log" 174 | 175 | "github.com/globalsign/mgo" 176 | ) 177 | 178 | const ( 179 | host = "127.0.0.1:27017" 180 | source = "admin" 181 | user = "user" 182 | pass = "123456" 183 | ) 184 | 185 | var globalS *mgo.Session 186 | 187 | func init() { 188 | dialInfo := &mgo.DialInfo{ 189 | Addrs: []string{host}, 190 | Source: source, 191 | Username: user, 192 | Password: pass, 193 | } 194 | s, err := mgo.DialWithInfo(dialInfo) 195 | if err != nil { 196 | log.Fatalln("create session error ", err) 197 | } 198 | globalS = s 199 | } 200 | 201 | func connect(db, collection string) (*mgo.Session, *mgo.Collection) { 202 | s := globalS.Copy() 203 | c := s.DB(db).C(collection) 204 | return s, c 205 | } 206 | 207 | func Insert(db, collection string, docs ...interface{}) error { 208 | ms, c := connect(db, collection) 209 | defer ms.Close() 210 | return c.Insert(docs...) 211 | } 212 | 213 | func FindOne(db, collection string, query, selector, result interface{}) error { 214 | ms, c := connect(db, collection) 215 | defer ms.Close() 216 | return c.Find(query).Select(selector).One(result) 217 | } 218 | 219 | func FindAll(db, collection string, query, selector, result interface{}) error { 220 | ms, c := connect(db, collection) 221 | defer ms.Close() 222 | return c.Find(query).Select(selector).All(result) 223 | } 224 | 225 | func Update(db, collection string, query, update interface{}) error { 226 | ms, c := connect(db, collection) 227 | defer ms.Close() 228 | return c.Update(query, update) 229 | } 230 | 231 | func Remove(db, collection string, query interface{}) error { 232 | ms, c := connect(db, collection) 233 | defer ms.Close() 234 | return c.Remove(query) 235 | } 236 | 237 | ``` 238 | 239 | * 业务逻辑层 `models/movies.go` 240 | 241 | ``` 242 | package models 243 | 244 | import "github.com/globalsign/mgo/bson" 245 | 246 | type Movies struct { 247 | Id bson.ObjectId `bson:"_id" json:"id"` 248 | Name string `bson:"name" json:"name"` 249 | CoverImage string `bson:"cover_image" json:"cover_image"` 250 | Description string `bson:"description" json:"description"` 251 | } 252 | 253 | const ( 254 | db = "Movies" 255 | collection = "MovieModel" 256 | ) 257 | 258 | func (m *Movies) InsertMovie(movie Movies) error { 259 | return Insert(db, collection, movie) 260 | } 261 | 262 | func (m *Movies) FindAllMovies() ([]Movies, error) { 263 | var result []Movies 264 | err := FindAll(db, collection, nil, nil, &result) 265 | return result, err 266 | } 267 | 268 | func (m *Movies) FindMovieById(id string) (Movies, error) { 269 | var result Movies 270 | err := FindOne(db, collection, bson.M{"_id": bson.ObjectIdHex(id)}, nil, &result) 271 | return result, err 272 | } 273 | 274 | func (m *Movies) UpdateMovie(movie Movies) error { 275 | return Update(db, collection, bson.M{"_id": movie.Id}, movie) 276 | } 277 | 278 | func (m *Movies) RemoveMovie(id string) error { 279 | return Remove(db, collection, bson.M{"_id": bson.ObjectIdHex(id)}) 280 | } 281 | 282 | ``` 283 | 284 | #### 控制器逻辑 285 | 286 | * CreateMovie 287 | 288 | ``` 289 | func CreateMovie(w http.ResponseWriter, r *http.Request) { 290 | defer r.Body.Close() 291 | var movie models.Movies 292 | if err := json.NewDecoder(r.Body).Decode(&movie); err != nil { 293 | responseWithJson(w, http.StatusBadRequest, "Invalid request payload") 294 | return 295 | } 296 | movie.Id = bson.NewObjectId() 297 | if err := dao.InsertMovie(movie); err != nil { 298 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 299 | return 300 | } 301 | responseWithJson(w, http.StatusCreated, movie) 302 | } 303 | ``` 304 | 305 | 使用 `Postman` 或 `curl`进行测试 306 | 307 | * AllMovies 308 | 309 | ``` 310 | func AllMovies(w http.ResponseWriter, r *http.Request) { 311 | defer r.Body.Close() 312 | var movies []models.Movies 313 | movies, err := dao.FindAllMovies() 314 | if err != nil { 315 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 316 | return 317 | } 318 | responseWithJson(w, http.StatusOK, movies) 319 | 320 | } 321 | ``` 322 | 323 | * FindMovie 324 | 325 | ``` 326 | func FindMovie(w http.ResponseWriter, r *http.Request) { 327 | vars := mux.Vars(r) 328 | id := vars["id"] 329 | result, err := dao.FindMovieById(id) 330 | if err != nil { 331 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 332 | return 333 | } 334 | responseWithJson(w, http.StatusOK, result) 335 | } 336 | ``` 337 | 338 | > http://127.0.0.1:8080/movies/5b45ef3a9d5e3e197c15e774 339 | 340 | * UpdateMovie 341 | 342 | ``` 343 | func UpdateMovie(w http.ResponseWriter, r *http.Request) { 344 | defer r.Body.Close() 345 | var params models.Movies 346 | if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { 347 | responseWithJson(w, http.StatusBadRequest, "Invalid request payload") 348 | return 349 | } 350 | if err := dao.UpdateMovie(params); err != nil { 351 | responseWithJson(w, http.StatusInternalServerError, err.Error()) 352 | return 353 | } 354 | responseWithJson(w, http.StatusOK, map[string]string{"result": "success"}) 355 | } 356 | ``` 357 | 358 | * DeleteMovie 359 | 360 | ``` 361 | func DeleteMovie(w http.ResponseWriter, r *http.Request) { 362 | vars := mux.Vars(r) 363 | id := vars["id"] 364 | if err := dao.RemoveMovie(id); err != nil { 365 | responseWithJson(w, http.StatusBadRequest, "Invalid request payload") 366 | return 367 | } 368 | 369 | responseWithJson(w, http.StatusOK, map[string]string{"result": "success"}) 370 | } 371 | ``` 372 | --------------------------------------------------------------------------------