Skip to content

Commit c8cea96

Browse files
committed
create bookings service
1 parent 62cc678 commit c8cea96

File tree

8 files changed

+354
-0
lines changed

8 files changed

+354
-0
lines changed

bookings/cmd/app/handlers.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
7+
"github.com/gorilla/mux"
8+
"github.com/mikebellcoder/microservices-docker-go-mongodb/bookings/pkg/models"
9+
)
10+
11+
func (app *application) all(w http.ResponseWriter, r *http.Request) {
12+
// Get all bookings stored
13+
bookings, err := app.bookings.All()
14+
if err != nil {
15+
app.serverError(w, err)
16+
}
17+
18+
// Convert booking list into json encoding
19+
b, err := json.Marshal(bookings)
20+
if err != nil {
21+
app.serverError(w, err)
22+
}
23+
24+
app.infoLog.Println("Bookings have been listed")
25+
26+
// Send response back
27+
w.Header().Set("Content-Type", "application/json")
28+
w.WriteHeader(http.StatusOK)
29+
w.Write(b)
30+
}
31+
32+
func (app *application) findByID(w http.ResponseWriter, r *http.Request) {
33+
// Get id from incoming url
34+
vars := mux.Vars(r)
35+
id := vars["id"]
36+
37+
// Find booking by id
38+
m, err := app.bookings.FindByID(id)
39+
if err != nil {
40+
if err.Error() == "ErrNoDocuments" {
41+
app.infoLog.Println("Booking not found")
42+
return
43+
}
44+
45+
app.serverError(w, err)
46+
}
47+
48+
// Convert booking to json encoding
49+
b, err := json.Marshal(m)
50+
if err != nil {
51+
app.serverError(w, err)
52+
}
53+
54+
app.infoLog.Println("Found a booking")
55+
56+
// Send response back
57+
w.Header().Set("Content-Type", "application/json")
58+
w.WriteHeader(http.StatusOK)
59+
w.Write(b)
60+
}
61+
62+
func (app *application) insert(w http.ResponseWriter, r *http.Request) {
63+
// Define booking model
64+
var m models.Booking
65+
66+
// Get request information
67+
err := json.NewDecoder(r.Body).Decode(&m)
68+
if err != nil {
69+
app.serverError(w, err)
70+
}
71+
72+
// Insert new booking
73+
insertResult, err := app.bookings.Insert(m)
74+
if err != nil {
75+
app.serverError(w, err)
76+
}
77+
78+
app.infoLog.Printf("New booking has been created, id=%s\n", insertResult.InsertedID)
79+
}
80+
81+
func (app *application) delete(w http.ResponseWriter, r *http.Request) {
82+
// Get id from incoming url
83+
vars := mux.Vars(r)
84+
id := vars["id"]
85+
86+
// Delete booking by id
87+
deleteResult, err := app.bookings.Delete(id)
88+
if err != nil {
89+
app.serverError(w, err)
90+
}
91+
92+
app.infoLog.Printf("Deleted %d booking(s)\n", deleteResult.DeletedCount)
93+
}

bookings/cmd/app/helpers.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"runtime/debug"
7+
)
8+
9+
func (app *application) serverError(w http.ResponseWriter, err error) {
10+
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
11+
app.errorLog.Output(2, trace)
12+
13+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
14+
}
15+
16+
func (app *application) clientError(w http.ResponseWriter, status int) {
17+
http.Error(w, http.StatusText(status), status)
18+
}

bookings/cmd/app/main.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"net/http"
9+
"os"
10+
"time"
11+
12+
"github.com/mikebellcoder/microservices-docker-go-mongodb/bookings/pkg/models/mongodb"
13+
"go.mongodb.org/mongo-driver/mongo"
14+
"go.mongodb.org/mongo-driver/mongo/options"
15+
)
16+
17+
type application struct {
18+
errorLog *log.Logger
19+
infoLog *log.Logger
20+
bookings *mongodb.BookingModel
21+
}
22+
23+
func main() {
24+
// Define command-line flags
25+
serverAddr := flag.String("serverAddr", "", "HTTP server network address")
26+
serverPort := flag.Int("serverPort", 4000, "HTTP server network port")
27+
mongoURI := flag.String("mongoURI", "mongodb://localhost:27017", "Database hostname url")
28+
mongoDatabase := flag.String("mongoDatabase", "bookings", "Database name")
29+
enableCredentials := flag.Bool("enableCredentials", false, "Enable the use of credentials for mongo connection")
30+
flag.Parse()
31+
32+
// Create loggers
33+
infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)
34+
errLog := log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile)
35+
36+
// Create client config
37+
co := options.Client().ApplyURI(*mongoURI)
38+
if *enableCredentials {
39+
co.Auth = &options.Credential{
40+
Username: os.Getenv("MONGODB_USERNAME"),
41+
Password: os.Getenv("MONGODB_PASSWORD"),
42+
}
43+
}
44+
45+
// Establish DB connection
46+
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
47+
defer cancel()
48+
49+
client, err := mongo.Connect(ctx, co)
50+
if err != nil {
51+
errLog.Fatal(err)
52+
}
53+
54+
defer func() {
55+
if err = client.Disconnect(ctx); err != nil {
56+
panic(err)
57+
}
58+
}()
59+
60+
// Initialize new app instance
61+
app := &application{
62+
infoLog: infoLog,
63+
errorLog: errLog,
64+
bookings: &mongodb.BookingModel{
65+
C: client.Database(*mongoDatabase).Collection("bookings"),
66+
},
67+
}
68+
69+
// Initialize an http.Server
70+
serverURI := fmt.Sprintf("%s:%d", *serverAddr, *serverPort)
71+
srv := &http.Server{
72+
Addr: serverURI,
73+
ErrorLog: errLog,
74+
Handler: app.routes(),
75+
IdleTimeout: time.Minute,
76+
ReadTimeout: 5 * time.Second,
77+
WriteTimeout: 10 * time.Second,
78+
}
79+
80+
infoLog.Printf("Starting server on %s\n", serverURI)
81+
err = srv.ListenAndServe()
82+
errLog.Fatal(err)
83+
}

bookings/cmd/app/routes.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package main
2+
3+
import "github.com/gorilla/mux"
4+
5+
func (app *application) routes() *mux.Router {
6+
// Register handler functions.
7+
r := mux.NewRouter()
8+
r.HandleFunc("/api/bookings/", app.all).Methods("GET")
9+
r.HandleFunc("/api/bookings/{id}", app.findByID).Methods("GET")
10+
r.HandleFunc("/api/bookings/", app.insert).Methods("POST")
11+
r.HandleFunc("/api/bookings/{id}", app.delete).Methods("DELETE")
12+
13+
return r
14+
}

bookings/go.mod

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module github.com/mikebellcoder/microservices-docker-go-mongodb/bookings
2+
3+
go 1.22.5
4+
5+
require (
6+
github.com/golang/snappy v0.0.4 // indirect
7+
github.com/gorilla/mux v1.8.1 // indirect
8+
github.com/klauspost/compress v1.16.7 // indirect
9+
github.com/montanaflynn/stats v0.7.1 // indirect
10+
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
11+
github.com/xdg-go/scram v1.1.2 // indirect
12+
github.com/xdg-go/stringprep v1.0.4 // indirect
13+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
14+
go.mongodb.org/mongo-driver v1.17.2 // indirect
15+
golang.org/x/crypto v0.26.0 // indirect
16+
golang.org/x/sync v0.8.0 // indirect
17+
golang.org/x/text v0.17.0 // indirect
18+
)

bookings/go.sum

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
2+
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
3+
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
4+
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
5+
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
6+
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
7+
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
8+
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
9+
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
10+
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
11+
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
12+
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
13+
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
14+
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
15+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
16+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
17+
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
18+
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
19+
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
20+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
21+
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
22+
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
23+
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
24+
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
25+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
26+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
27+
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
28+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
29+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
30+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
31+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
32+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
33+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
34+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
35+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
36+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
37+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
38+
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
39+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
40+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
41+
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
42+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
43+
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
44+
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
45+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
46+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
47+
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
48+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

bookings/pkg/models/models.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package models
2+
3+
import "go.mongodb.org/mongo-driver/bson/primitive"
4+
5+
// Booking is used to represent booking profile data
6+
type Booking struct {
7+
ID primitive.ObjectID `bson:"_id,omitempty"`
8+
UserID string `bson:"userid"`
9+
ShowtimeID string `bson:"showtimeid"`
10+
Movies []string `bson:"movies"`
11+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package mongodb
2+
3+
import (
4+
"context"
5+
"errors"
6+
7+
"github.com/mikebellcoder/microservices-docker-go-mongodb/bookings/pkg/models"
8+
"go.mongodb.org/mongo-driver/bson"
9+
"go.mongodb.org/mongo-driver/bson/primitive"
10+
"go.mongodb.org/mongo-driver/mongo"
11+
)
12+
13+
// BookingModel represents a mgo database session with a booking data model
14+
type BookingModel struct {
15+
C *mongo.Collection
16+
}
17+
18+
// All method will be used to get all records from bookings collection
19+
func (m *BookingModel) All() ([]models.Booking, error) {
20+
// Define variables
21+
ctx := context.TODO()
22+
b := []models.Booking{}
23+
24+
// Find all bookings
25+
bookingCursor, err := m.C.Find(ctx, bson.M{})
26+
if err != nil {
27+
return nil, err
28+
}
29+
err = bookingCursor.All(ctx, &b)
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
return b, err
35+
}
36+
37+
// FindByID will be used to find a booking registry by id
38+
func (m *BookingModel) FindByID(id string) (*models.Booking, error) {
39+
p, err := primitive.ObjectIDFromHex(id)
40+
if err != nil {
41+
return nil, err
42+
}
43+
44+
var booking = models.Booking{}
45+
err = m.C.FindOne(context.TODO(), bson.M{"_id": p}).Decode(&booking)
46+
if err != nil {
47+
// Check if the booking was not found
48+
if err == mongo.ErrNoDocuments {
49+
return nil, errors.New("ErrNoDocuments")
50+
}
51+
return nil, err
52+
}
53+
54+
return &booking, nil
55+
}
56+
57+
// Insert will be used to insert a new booking registry
58+
func (m *BookingModel) Insert(booking models.Booking) (*mongo.InsertOneResult, error) {
59+
return m.C.InsertOne(context.TODO(), booking)
60+
}
61+
62+
// Delete will be used to delete a booking registry
63+
func (m *BookingModel) Delete(id string) (*mongo.DeleteResult, error) {
64+
p, err := primitive.ObjectIDFromHex(id)
65+
if err != nil {
66+
return nil, err
67+
}
68+
return m.C.DeleteOne(context.TODO(), bson.M{"_id": p})
69+
}

0 commit comments

Comments
 (0)