mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
add tutorial for the official mongodb go driver
Former-commit-id: 8353dd101c37c223bba404403f9f8fa2d042fede
This commit is contained in:
parent
680b5a0923
commit
4284739151
|
@ -17,6 +17,10 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
|||
|
||||
**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you.
|
||||
|
||||
# Soon
|
||||
|
||||
Coming soon, stay tuned by reading the [PR](https://github.com/kataras/iris/pull/1175) progress.
|
||||
|
||||
# Fr, 11 January 2019 | v11.1.1
|
||||
|
||||
Happy new year! This is a minor release, contains mostly bug fixes.
|
||||
|
|
|
@ -1020,7 +1020,7 @@ Iris, unlike others, is 100% compatible with the standards and that's why the ma
|
|||
|
||||
## Support
|
||||
|
||||
- [HISTORY](HISTORY.md#fr-11-january-2019--v1111) file is your best friend, it contains information about the latest features and changes
|
||||
- [HISTORY](HISTORY.md#soon) file is your best friend, it contains information about the latest features and changes
|
||||
- Did you happen to find a bug? Post it at [github issues](https://github.com/kataras/iris/issues)
|
||||
- Do you have any questions or need to speak with someone experienced to solve a problem at real-time? Join us to the [community chat](https://chat.iris-go.com)
|
||||
- Complete our form-based user experience report by clicking [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
11.1.1:https://github.com/kataras/iris/blob/master/HISTORY.md#fr-11-january-2019--v1111
|
||||
11.2.0:https://github.com/kataras/iris/blob/master/HISTORY.md#soon
|
2
_examples/tutorial/mongodb/.env
Normal file
2
_examples/tutorial/mongodb/.env
Normal file
|
@ -0,0 +1,2 @@
|
|||
PORT=8080
|
||||
DSN=mongodb://localhost:27017
|
BIN
_examples/tutorial/mongodb/0_create_movie.png
Normal file
BIN
_examples/tutorial/mongodb/0_create_movie.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
BIN
_examples/tutorial/mongodb/1_update_movie.png
Normal file
BIN
_examples/tutorial/mongodb/1_update_movie.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
BIN
_examples/tutorial/mongodb/2_get_all_movies.png
Normal file
BIN
_examples/tutorial/mongodb/2_get_all_movies.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
BIN
_examples/tutorial/mongodb/3_get_movie.png
Normal file
BIN
_examples/tutorial/mongodb/3_get_movie.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
BIN
_examples/tutorial/mongodb/4_delete_movie.png
Normal file
BIN
_examples/tutorial/mongodb/4_delete_movie.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
58
_examples/tutorial/mongodb/README.md
Normal file
58
_examples/tutorial/mongodb/README.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Build RESTful API with the official MongoDB Go Driver and Iris
|
||||
|
||||
Article is coming soon, follow and stay tuned
|
||||
|
||||
- <https://medium.com/@kataras>
|
||||
- <https://dev.to/kataras>
|
||||
|
||||
Read [the fully functional example](main.go).
|
||||
|
||||
```sh
|
||||
$ go get -u github.com/mongodb/mongo-go-driver
|
||||
$ go get -u github.com/joho/godotenv
|
||||
```
|
||||
|
||||
|
||||
```sh
|
||||
# .env file contents
|
||||
PORT=8080
|
||||
DSN=mongodb://localhost:27017
|
||||
```
|
||||
|
||||
```sh
|
||||
$ go run main.go
|
||||
> 2019/01/28 05:17:59 Loading environment variables from file: .env
|
||||
> 2019/01/28 05:17:59 ◽ PORT=8080
|
||||
> 2019/01/28 05:17:59 ◽ DSN=mongodb://localhost:27017
|
||||
> Now listening on: http://localhost:8080
|
||||
```
|
||||
|
||||
```sh
|
||||
GET : http://localhost:8080/api/store/movies
|
||||
POST : http://localhost:8080/api/store/movies
|
||||
GET : http://localhost:8080/api/store/movies/{id}
|
||||
PUT : http://localhost:8080/api/store/movies/{id}
|
||||
DELETE : http://localhost:8080/api/store/movies/{id}
|
||||
```
|
||||
|
||||
## Screens
|
||||
|
||||
### Add a Movie
|
||||
![](0_create_movie.png)
|
||||
|
||||
### Update a Movie
|
||||
|
||||
![](1_update_movie.png)
|
||||
|
||||
### Get all Movies
|
||||
|
||||
![](2_get_all_movies.png)
|
||||
|
||||
### Get a Movie by its ID
|
||||
|
||||
![](3_get_movie.png)
|
||||
|
||||
### Delete a Movie by its ID
|
||||
|
||||
![](4_delete_movie.png)
|
||||
|
101
_examples/tutorial/mongodb/api/store/movie.go
Normal file
101
_examples/tutorial/mongodb/api/store/movie.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
package storeapi
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/_examples/tutorial/mongodb/httputil"
|
||||
"github.com/kataras/iris/_examples/tutorial/mongodb/store"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
type MovieHandler struct {
|
||||
service store.MovieService
|
||||
}
|
||||
|
||||
func NewMovieHandler(service store.MovieService) *MovieHandler {
|
||||
return &MovieHandler{service: service}
|
||||
}
|
||||
|
||||
func (h *MovieHandler) GetAll(ctx iris.Context) {
|
||||
movies, err := h.service.GetAll(nil)
|
||||
if err != nil {
|
||||
httputil.InternalServerErrorJSON(ctx, err, "Server was unable to retrieve all movies")
|
||||
return
|
||||
}
|
||||
|
||||
if movies == nil {
|
||||
// will return "null" if empty, with this "trick" we return "[]" json.
|
||||
movies = make([]store.Movie, 0)
|
||||
}
|
||||
|
||||
ctx.JSON(movies)
|
||||
}
|
||||
|
||||
func (h *MovieHandler) Get(ctx iris.Context) {
|
||||
id := ctx.Params().Get("id")
|
||||
|
||||
m, err := h.service.GetByID(nil, id)
|
||||
if err != nil {
|
||||
if err == store.ErrNotFound {
|
||||
ctx.NotFound()
|
||||
} else {
|
||||
httputil.InternalServerErrorJSON(ctx, err, "Server was unable to retrieve movie [%s]", id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(m)
|
||||
}
|
||||
|
||||
func (h *MovieHandler) Add(ctx iris.Context) {
|
||||
m := new(store.Movie)
|
||||
|
||||
err := ctx.ReadJSON(m)
|
||||
if err != nil {
|
||||
httputil.FailJSON(ctx, iris.StatusBadRequest, err, "Malformed request payload")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.Create(nil, m)
|
||||
if err != nil {
|
||||
httputil.InternalServerErrorJSON(ctx, err, "Server was unable to create a movie")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.StatusCode(iris.StatusCreated)
|
||||
ctx.JSON(m)
|
||||
}
|
||||
|
||||
func (h *MovieHandler) Update(ctx iris.Context) {
|
||||
id := ctx.Params().Get("id")
|
||||
|
||||
var m store.Movie
|
||||
err := ctx.ReadJSON(&m)
|
||||
if err != nil {
|
||||
httputil.FailJSON(ctx, iris.StatusBadRequest, err, "Malformed request payload")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.Update(nil, id, m)
|
||||
if err != nil {
|
||||
if err == store.ErrNotFound {
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
httputil.InternalServerErrorJSON(ctx, err, "Server was unable to update movie [%s]", id)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *MovieHandler) Delete(ctx iris.Context) {
|
||||
id := ctx.Params().Get("id")
|
||||
|
||||
err := h.service.Delete(nil, id)
|
||||
if err != nil {
|
||||
if err == store.ErrNotFound {
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
httputil.InternalServerErrorJSON(ctx, err, "Server was unable to delete movie [%s]", id)
|
||||
return
|
||||
}
|
||||
}
|
71
_examples/tutorial/mongodb/env/env.go
vendored
Normal file
71
_examples/tutorial/mongodb/env/env.go
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var (
|
||||
// Port is the PORT environment variable or 8080 if missing.
|
||||
// Used to open the tcp listener for our web server.
|
||||
Port string
|
||||
// DSN is the DSN environment variable or mongodb://localhost:27017 if missing.
|
||||
// Used to connect to the mongodb.
|
||||
DSN string
|
||||
)
|
||||
|
||||
func parse() {
|
||||
Port = getDefault("PORT", "8080")
|
||||
DSN = getDefault("DSN", "mongodb://localhost:27017")
|
||||
}
|
||||
|
||||
// Load loads environment variables that are being used across the whole app.
|
||||
// Loading from file(s), i.e .env or dev.env
|
||||
//
|
||||
// Example of a 'dev.env':
|
||||
// PORT=8080
|
||||
// DSN=mongodb://localhost:27017
|
||||
//
|
||||
// After `Load` the callers can get an environment variable via `os.Getenv`.
|
||||
func Load(envFileName string) {
|
||||
if args := os.Args; len(args) > 1 && args[1] == "help" {
|
||||
fmt.Fprintln(os.Stderr, "https://github.com/kataras/iris/blob/master/_examples/tutorials/mongodb/README.md")
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
log.Printf("Loading environment variables from file: %s\n", envFileName)
|
||||
// If more than one filename passed with comma separated then load from all
|
||||
// of these, a env file can be a partial too.
|
||||
envFiles := strings.Split(envFileName, ",")
|
||||
for i := range envFiles {
|
||||
if filepath.Ext(envFiles[i]) == "" {
|
||||
envFiles[i] += ".env"
|
||||
}
|
||||
}
|
||||
|
||||
if err := godotenv.Load(envFiles...); err != nil {
|
||||
panic(fmt.Sprintf("error loading environment variables from [%s]: %v", envFileName, err))
|
||||
}
|
||||
|
||||
envMap, _ := godotenv.Read(envFiles...)
|
||||
for k, v := range envMap {
|
||||
log.Printf("◽ %s=%s\n", k, v)
|
||||
}
|
||||
|
||||
parse()
|
||||
}
|
||||
|
||||
func getDefault(key string, def string) string {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
os.Setenv(key, def)
|
||||
value = def
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
130
_examples/tutorial/mongodb/httputil/error.go
Normal file
130
_examples/tutorial/mongodb/httputil/error.go
Normal file
|
@ -0,0 +1,130 @@
|
|||
package httputil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
var validStackFuncs = []func(string) bool{
|
||||
func(file string) bool {
|
||||
return strings.Contains(file, "/mongodb/api/")
|
||||
},
|
||||
}
|
||||
|
||||
// RuntimeCallerStack returns the app's `file:line` stacktrace
|
||||
// to give more information about an error cause.
|
||||
func RuntimeCallerStack() (s string) {
|
||||
var pcs [10]uintptr
|
||||
n := runtime.Callers(1, pcs[:])
|
||||
frames := runtime.CallersFrames(pcs[:n])
|
||||
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
for _, fn := range validStackFuncs {
|
||||
if fn(frame.File) {
|
||||
s += fmt.Sprintf("\n\t\t\t%s:%d", frame.File, frame.Line)
|
||||
}
|
||||
}
|
||||
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// HTTPError describes an HTTP error.
|
||||
type HTTPError struct {
|
||||
error
|
||||
Stack string `json:"-"` // the whole stacktrace.
|
||||
CallerStack string `json:"-"` // the caller, file:lineNumber
|
||||
When time.Time `json:"-"` // the time that the error occurred.
|
||||
// ErrorCode int: maybe a collection of known error codes.
|
||||
StatusCode int `json:"statusCode"`
|
||||
// could be named as "reason" as well
|
||||
// it's the message of the error.
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func newError(statusCode int, err error, format string, args ...interface{}) HTTPError {
|
||||
if format == "" {
|
||||
format = http.StatusText(statusCode)
|
||||
}
|
||||
|
||||
desc := fmt.Sprintf(format, args...)
|
||||
if err == nil {
|
||||
err = errors.New(desc)
|
||||
}
|
||||
|
||||
return HTTPError{
|
||||
err,
|
||||
string(debug.Stack()),
|
||||
RuntimeCallerStack(),
|
||||
time.Now(),
|
||||
statusCode,
|
||||
desc,
|
||||
}
|
||||
}
|
||||
|
||||
func (err HTTPError) writeHeaders(ctx iris.Context) {
|
||||
ctx.StatusCode(err.StatusCode)
|
||||
ctx.Header("X-Content-Type-Options", "nosniff")
|
||||
}
|
||||
|
||||
// LogFailure will print out the failure to the "logger".
|
||||
func LogFailure(logger io.Writer, ctx iris.Context, err HTTPError) {
|
||||
timeFmt := err.When.Format("2006/01/02 15:04:05")
|
||||
firstLine := fmt.Sprintf("%s %s: %s", timeFmt, http.StatusText(err.StatusCode), err.Error())
|
||||
whitespace := strings.Repeat(" ", len(timeFmt)+1)
|
||||
fmt.Fprintf(logger, "%s\n%sIP: %s\n%sURL: %s\n%sSource: %s\n",
|
||||
firstLine, whitespace, ctx.RemoteAddr(), whitespace, ctx.FullRequestURI(), whitespace, err.CallerStack)
|
||||
}
|
||||
|
||||
// Fail will send the status code, write the error's reason
|
||||
// and return the HTTPError for further use, i.e logging, see `InternalServerError`.
|
||||
func Fail(ctx iris.Context, statusCode int, err error, format string, args ...interface{}) HTTPError {
|
||||
httpErr := newError(statusCode, err, format, args...)
|
||||
httpErr.writeHeaders(ctx)
|
||||
|
||||
ctx.WriteString(httpErr.Description)
|
||||
return httpErr
|
||||
}
|
||||
|
||||
// FailJSON will send to the client the error data as JSON.
|
||||
// Useful for APIs.
|
||||
func FailJSON(ctx iris.Context, statusCode int, err error, format string, args ...interface{}) HTTPError {
|
||||
httpErr := newError(statusCode, err, format, args...)
|
||||
httpErr.writeHeaders(ctx)
|
||||
|
||||
ctx.JSON(httpErr)
|
||||
|
||||
return httpErr
|
||||
}
|
||||
|
||||
// InternalServerError logs to the server's terminal
|
||||
// and dispatches to the client the 500 Internal Server Error.
|
||||
// Internal Server errors are critical, so we log them to the `os.Stderr`.
|
||||
func InternalServerError(ctx iris.Context, err error, format string, args ...interface{}) {
|
||||
LogFailure(os.Stderr, ctx, Fail(ctx, iris.StatusInternalServerError, err, format, args...))
|
||||
}
|
||||
|
||||
// InternalServerErrorJSON acts exactly like `InternalServerError` but instead it sends the data as JSON.
|
||||
// Useful for APIs.
|
||||
func InternalServerErrorJSON(ctx iris.Context, err error, format string, args ...interface{}) {
|
||||
LogFailure(os.Stderr, ctx, FailJSON(ctx, iris.StatusInternalServerError, err, format, args...))
|
||||
}
|
||||
|
||||
// UnauthorizedJSON sends JSON format of StatusUnauthorized(401) HTTPError value.
|
||||
func UnauthorizedJSON(ctx iris.Context, err error, format string, args ...interface{}) HTTPError {
|
||||
return FailJSON(ctx, iris.StatusUnauthorized, err, format, args...)
|
||||
}
|
81
_examples/tutorial/mongodb/main.go
Normal file
81
_examples/tutorial/mongodb/main.go
Normal file
|
@ -0,0 +1,81 @@
|
|||
package main
|
||||
|
||||
// go get -u github.com/mongodb/mongo-go-driver
|
||||
// go get -u github.com/joho/godotenv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
// APIs
|
||||
storeapi "github.com/kataras/iris/_examples/tutorial/mongodb/api/store"
|
||||
|
||||
//
|
||||
"github.com/kataras/iris/_examples/tutorial/mongodb/env"
|
||||
"github.com/kataras/iris/_examples/tutorial/mongodb/store"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
|
||||
"github.com/mongodb/mongo-go-driver/mongo"
|
||||
)
|
||||
|
||||
const version = "0.0.1"
|
||||
|
||||
func init() {
|
||||
var envFileName = ".env"
|
||||
|
||||
flagset := flag.CommandLine
|
||||
flagset.StringVar(&envFileName, "env", envFileName, "the env file which web app will use to extract its environment variables")
|
||||
flag.CommandLine.Parse(os.Args[1:])
|
||||
|
||||
env.Load(envFileName)
|
||||
}
|
||||
|
||||
func main() {
|
||||
client, err := mongo.Connect(context.Background(), env.DSN)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = client.Ping(context.Background(), nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
db := client.Database("store")
|
||||
|
||||
var (
|
||||
// Collections.
|
||||
moviesCollection = db.Collection("movies")
|
||||
|
||||
// Services.
|
||||
movieService = store.NewMovieService(moviesCollection)
|
||||
)
|
||||
|
||||
app := iris.New()
|
||||
app.Use(func(ctx iris.Context) {
|
||||
ctx.Header("Server", "Iris MongoDB/"+version)
|
||||
ctx.Next()
|
||||
})
|
||||
|
||||
storeAPI := app.Party("/api/store")
|
||||
{
|
||||
movieHandler := storeapi.NewMovieHandler(movieService)
|
||||
storeAPI.Get("/movies", movieHandler.GetAll)
|
||||
storeAPI.Post("/movies", movieHandler.Add)
|
||||
storeAPI.Get("/movies/{id}", movieHandler.Get)
|
||||
storeAPI.Put("/movies/{id}", movieHandler.Update)
|
||||
storeAPI.Delete("/movies/{id}", movieHandler.Delete)
|
||||
}
|
||||
|
||||
// GET: http://localhost:8080/api/store/movies
|
||||
// POST: http://localhost:8080/api/store/movies
|
||||
// GET: http://localhost:8080/api/store/movies/{id}
|
||||
// PUT: http://localhost:8080/api/store/movies/{id}
|
||||
// DELETE: http://localhost:8080/api/store/movies/{id}
|
||||
app.Run(iris.Addr(fmt.Sprintf(":%s", env.Port)), iris.WithOptimizations)
|
||||
}
|
180
_examples/tutorial/mongodb/store/movie.go
Normal file
180
_examples/tutorial/mongodb/store/movie.go
Normal file
|
@ -0,0 +1,180 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/mongodb/mongo-go-driver/bson"
|
||||
"github.com/mongodb/mongo-go-driver/bson/primitive"
|
||||
"github.com/mongodb/mongo-go-driver/mongo"
|
||||
// up to you:
|
||||
// "github.com/mongodb/mongo-go-driver/mongo/options"
|
||||
)
|
||||
|
||||
type Movie struct {
|
||||
ID primitive.ObjectID `json:"_id" bson:"_id"` /* you need the bson:"_id" to be able to retrieve with ID filled */
|
||||
Name string `json:"name"`
|
||||
Cover string `json:"cover"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type MovieService interface {
|
||||
GetAll(ctx context.Context) ([]Movie, error)
|
||||
GetByID(ctx context.Context, id string) (Movie, error)
|
||||
Create(ctx context.Context, m *Movie) error
|
||||
Update(ctx context.Context, id string, m Movie) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
||||
|
||||
type movieService struct {
|
||||
C *mongo.Collection
|
||||
}
|
||||
|
||||
var _ MovieService = (*movieService)(nil)
|
||||
|
||||
func NewMovieService(collection *mongo.Collection) MovieService {
|
||||
// up to you:
|
||||
// indexOpts := new(options.IndexOptions)
|
||||
// indexOpts.SetName("movieIndex").
|
||||
// SetUnique(true).
|
||||
// SetBackground(true).
|
||||
// SetSparse(true)
|
||||
|
||||
// collection.Indexes().CreateOne(context.Background(), mongo.IndexModel{
|
||||
// Keys: []string{"_id", "name"},
|
||||
// Options: indexOpts,
|
||||
// })
|
||||
|
||||
return &movieService{C: collection}
|
||||
}
|
||||
|
||||
func (s *movieService) GetAll(ctx context.Context) ([]Movie, error) {
|
||||
// Note:
|
||||
// The mongodb's go-driver's docs says that you can pass `nil` to "find all" but this gives NilDocument error,
|
||||
// probably it's a bug or a documentation's mistake, you have to pass `bson.D{}` instead.
|
||||
cur, err := s.C.Find(ctx, bson.D{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cur.Close(ctx)
|
||||
|
||||
var results []Movie
|
||||
|
||||
for cur.Next(ctx) {
|
||||
if err = cur.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// elem := bson.D{}
|
||||
var elem Movie
|
||||
err = cur.Decode(&elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// results = append(results, Movie{ID: elem[0].Value.(primitive.ObjectID)})
|
||||
|
||||
results = append(results, elem)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func matchID(id string) (bson.D, error) {
|
||||
objectID, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter := bson.D{{Key: "_id", Value: objectID}}
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
var ErrNotFound = errors.New("not found")
|
||||
|
||||
func (s *movieService) GetByID(ctx context.Context, id string) (Movie, error) {
|
||||
var movie Movie
|
||||
filter, err := matchID(id)
|
||||
if err != nil {
|
||||
return movie, err
|
||||
}
|
||||
|
||||
err = s.C.FindOne(ctx, filter).Decode(&movie)
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return movie, ErrNotFound
|
||||
}
|
||||
return movie, err
|
||||
}
|
||||
|
||||
func (s *movieService) Create(ctx context.Context, m *Movie) error {
|
||||
if m.ID.IsZero() {
|
||||
m.ID = primitive.NewObjectID()
|
||||
}
|
||||
|
||||
_, err := s.C.InsertOne(ctx, m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The following doesn't work if you have the `bson:"_id` on Movie.ID field,
|
||||
// therefore we manually generate a new ID (look above).
|
||||
// res, err := ...InsertOne
|
||||
// objectID := res.InsertedID.(primitive.ObjectID)
|
||||
// m.ID = objectID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *movieService) Update(ctx context.Context, id string, m Movie) error {
|
||||
filter, err := matchID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update := bson.D{
|
||||
// {Key: "$set", Value: m},
|
||||
// }
|
||||
// ^ this will override all fields, you can do that, depending on your design. but let's check each field:
|
||||
elem := bson.D{}
|
||||
|
||||
if m.Name != "" {
|
||||
elem = append(elem, bson.E{Key: "name", Value: m.Name})
|
||||
}
|
||||
|
||||
if m.Description != "" {
|
||||
elem = append(elem, bson.E{Key: "description", Value: m.Description})
|
||||
}
|
||||
|
||||
if m.Cover != "" {
|
||||
elem = append(elem, bson.E{Key: "cover", Value: m.Cover})
|
||||
}
|
||||
|
||||
update := bson.D{
|
||||
{Key: "$set", Value: elem},
|
||||
}
|
||||
|
||||
_, err = s.C.UpdateOne(ctx, filter, update)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *movieService) Delete(ctx context.Context, id string) error {
|
||||
filter, err := matchID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.C.DeleteOne(ctx, filter)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
7
doc.go
7
doc.go
|
@ -27,7 +27,10 @@
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
Package iris provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app.
|
||||
Package iris implements the highest realistic performance, easy to learn Go web framework.
|
||||
Iris provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app.
|
||||
Low-level handlers compatible with `net/http` and high-level fastest MVC implementation and handlers dependency injection.
|
||||
Easy to learn for new gophers and advanced features for experienced, it goes as far as you dive into it!
|
||||
|
||||
Source code and other details for the project are available at GitHub:
|
||||
|
||||
|
@ -35,7 +38,7 @@ Source code and other details for the project are available at GitHub:
|
|||
|
||||
Current Version
|
||||
|
||||
11.1.1
|
||||
11.2.0
|
||||
|
||||
Installation
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user